-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3ffb734
commit b6e31d0
Showing
13 changed files
with
301 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// AnyLazy.swift | ||
// https://github.com/RougeWare/Swift-Lazy-Containers | ||
// | ||
// Created by Ky on 2024-12-26. | ||
// Copyright waived. No rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
|
||
/// The protocol to which all lazy protocols & types conform | ||
public protocol AnyLazy { | ||
|
||
/// The type of the value that will be lazily-initialized | ||
associatedtype Value | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// | ||
// AsyncLazy.swift | ||
// https://github.com/RougeWare/Swift-Lazy-Containers | ||
// | ||
// Created by Ky on 2024-12-26. | ||
// Copyright waived. No rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
|
||
//@propertyWrapper // Property wrappers currently cannot define an 'async' or 'throws' accessor | ||
public struct AsyncLazy<Value: Sendable> { | ||
|
||
private var _guts: AsyncValueReference<AsyncValueHolder> | ||
|
||
|
||
// init(initializer: @escaping AsyncInitializer<Value>) { | ||
// self.init(_guts: .init(wrappedValue: .unset(initializer: initializer))) | ||
// } | ||
|
||
|
||
/// Allows other initializers to have a shared point of initialization | ||
private init(_guts: AsyncValueReference<AsyncValueHolder>) { | ||
self._guts = _guts | ||
} | ||
|
||
|
||
public nonisolated var wrappedValue: Value { | ||
get async { await _guts.wrappedValue.wrappedValue } | ||
} | ||
} | ||
|
||
|
||
|
||
extension AsyncLazy: AsyncLazyProtocol | ||
where Value: Sendable | ||
{ | ||
public mutating func mutate(_ isolatedMutator: (inout Value) async -> Void) async { | ||
await _guts.mutate { asyncLazyContainerValueHolder in | ||
await asyncLazyContainerValueHolder.mutate { value in | ||
await isolatedMutator(&value) | ||
} | ||
} | ||
} | ||
|
||
public func get() async -> Value { | ||
await _guts.wrappedValue.wrappedValue | ||
} | ||
|
||
|
||
public nonisolated func set(to newValue: sending Value) async { | ||
await _guts.set(to: .hasValue(value: newValue)) | ||
} | ||
|
||
|
||
public static func preinitialized(_ initialValue: Value) -> Self { | ||
Self.init(_guts: .init(wrappedValue: .hasValue(value: initialValue))) | ||
} | ||
|
||
|
||
public var isInitialized: Bool { | ||
get async { await _guts.wrappedValue.hasValue } | ||
} | ||
|
||
|
||
public func initializeNow() async { | ||
await _guts.mutate { wrappedValue in | ||
await wrappedValue.initializeNow() | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
// MARK: - ValueHolder | ||
|
||
/// Takes care of keeping track of the state, value, and initializer of a lazy container, as needed | ||
//@propertyWrapper // Property wrappers currently cannot define an 'async' or 'throws' accessor | ||
public enum AsyncLazyContainerValueHolder<Value: Sendable>: Sendable { | ||
|
||
/// Indicates that a value has been cached, and contains that cached value | ||
case hasValue(value: Value) | ||
|
||
/// Indicates that the value has not yet been created, and contains its initializer | ||
case unset(initializer: AsyncInitializer<Value>) | ||
|
||
|
||
/// The value held inside this value holder. | ||
/// - Attention: Reading this value may mutate the state in order to compute the value. The complexity of that read | ||
/// operation is equal to the complexity of the initializer. | ||
public var wrappedValue: Value { | ||
mutating get async { | ||
switch self { | ||
case .hasValue(let value): | ||
return value | ||
|
||
case .unset(let initializer): | ||
let value = await initializer() | ||
self = .hasValue(value: value) | ||
return value | ||
} | ||
} | ||
} | ||
|
||
|
||
/// Sets the value asynchronously | ||
public mutating func set(to newValue: Value) async { | ||
self = .hasValue(value: newValue) | ||
} | ||
|
||
|
||
/// Indicates whether this holder actually holds a value. | ||
/// This will be `true` after reading or writing `wrappedValue`. | ||
public var hasValue: Bool { | ||
switch self { | ||
case .hasValue(value: _): return true | ||
case .unset(initializer: _): return false | ||
} | ||
} | ||
|
||
|
||
/// Immediately initializes the value held inside this value holder | ||
/// | ||
/// If this holder already contains a value, this does nothing | ||
mutating func initializeNow() async { | ||
switch self { | ||
case .hasValue(_): return | ||
case .unset(let initializer): | ||
self = await .hasValue(value: initializer()) | ||
} | ||
} | ||
|
||
|
||
mutating func mutate(_ isolatedMutator: (inout Value) async -> Void) async { | ||
var wrappedValue = await self.wrappedValue | ||
await isolatedMutator(&wrappedValue) | ||
await self.set(to: wrappedValue) | ||
} | ||
} | ||
|
||
|
||
|
||
|
||
public extension AnyLazy { | ||
|
||
/// Takes care of keeping track of the state, value, and initializer as needed | ||
typealias AsyncValueHolder = AsyncLazyContainerValueHolder<Value> | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// | ||
// AsyncLazyProtocol.swift | ||
// https://github.com/RougeWare/Swift-Lazy-Containers | ||
// | ||
// Created by Ky on 2024-12-26. | ||
// Copyright waived. No rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
|
||
/// Simply initializes a value | ||
public typealias AsyncInitializer<Value> = @Sendable () async -> Value | ||
|
||
|
||
|
||
/// Defines how a lazy container should look when it performs all its operations asynchronously | ||
public protocol AsyncLazyProtocol: AnyLazy { | ||
|
||
/// Gets the value, possibly initializing it first | ||
mutating func get() async -> Value | ||
|
||
|
||
/// Sets the value asynchronously | ||
mutating func set(to newValue: sending Value) async // If you feel like you want this to be nonmutating, see https://GitHub.com/RougeWare/Swift-Safe-Pointer | ||
|
||
|
||
/// Mutate the value within the context of this container | ||
/// - Parameter isolatedMutator: Mutates the wrapped value within the proper isolation context | ||
mutating func mutate(_ isolatedMutator: (inout Value) async -> Void) async | ||
|
||
|
||
/// Indicates whether the value has indeed been initialized | ||
var isInitialized: Bool { get async } | ||
|
||
|
||
/// Immediately initializes the value held inside this lazy container | ||
/// | ||
/// If this holder already contains a value, this does nothing | ||
// https://github.com/RougeWare/Swift-Lazy-Containers/issues/40 | ||
mutating func initializeNow() async | ||
|
||
|
||
/// Creates a lazy container that already contains an initialized value. | ||
/// | ||
/// This is useful when you need a uniform API (for instance, when implementing a protocol that requires a `Lazy`), | ||
/// but require it to already hold a value up-front | ||
/// | ||
/// - Parameter initialValue: The value to immediately store in the otherwise-lazy container | ||
static func preinitialized(_ initialValue: Value) -> Self | ||
} | ||
|
||
|
||
|
||
// MARK: - ValueReference | ||
|
||
/// Allows you to use reference-semantics to hold a value inside a lazy container | ||
//@propertyWrapper // Property wrappers currently cannot define an 'async' or 'throws' accessor | ||
public final actor LazyAsyncValueReference<Value: Sendable & Copyable> { | ||
|
||
/// Holds some value- or reference-passed instance inside a reference-passed one | ||
public var wrappedValue: Value | ||
|
||
|
||
/// Creates a reference to the given value- or reference-passed instance | ||
/// | ||
/// - Parameter wrappedValue: The instance to wrap | ||
public init(wrappedValue: Value) { | ||
self.wrappedValue = wrappedValue | ||
} | ||
|
||
|
||
func set(to newValue: Value) { | ||
wrappedValue = newValue | ||
} | ||
|
||
|
||
func mutate(_ isolatedMutator: @Sendable (inout Value) async -> Void) async { | ||
var wrappedValue = self.wrappedValue | ||
await isolatedMutator(&wrappedValue) | ||
self.wrappedValue = wrappedValue | ||
} | ||
} | ||
|
||
|
||
|
||
public extension AnyLazy { | ||
|
||
/// Allows you to use reference semantics to hold a value inside a lazy container. | ||
typealias AsyncValueReference = LazyAsyncValueReference | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.