-
-
Save akbashev/eb9d4198b0182b156b076704bcb32d12 to your computer and use it in GitHub Desktop.
Promised values in Swift Concurrency
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
/// Wrapper around a lazily resolved using checked continuation. | |
/// | |
/// Usage: | |
/// | |
/// ``` | |
/// let promiseA = Promised<String>() | |
/// async let a1 = promiseA.value | |
/// promiseA.resolve(with: "AAA") | |
/// let a2 = try await promiseA.value | |
/// print(try await a1, a2) | |
/// ``` | |
public actor Promised<WrappedValue: Sendable> { | |
private var _result: Result<WrappedValue, any Error>? | |
private var observers: [CheckedContinuation<WrappedValue, any Error>] = [] | |
public var value: WrappedValue { | |
get async throws { | |
switch _result { | |
case .success(let value): | |
return value | |
case .failure(let failure): | |
throw failure | |
case .none: | |
return try await withCheckedThrowingContinuation(add(continuation:)) | |
} | |
} | |
} | |
public nonisolated func resolve(with value: WrappedValue) { | |
catching(.success(value)) | |
} | |
public nonisolated func reject(with error: any Error) { | |
catching(.failure(error)) | |
} | |
public nonisolated func catching(_ result: Result<WrappedValue, any Error>) { | |
Task { await _resolve(result: result) } | |
} | |
private func _resolve(result: Result<WrappedValue, any Error>) { | |
switch _result { | |
case .none: | |
self._result = result | |
for continuation in observers { | |
continuation.resume(with: result) | |
} | |
case .some: | |
break | |
} | |
} | |
private func add( | |
continuation: CheckedContinuation<WrappedValue, any Error> | |
) { | |
observers.append(continuation) | |
} | |
public init() {} | |
} | |
// Usefull when you just need to wait for some future void call (like viewDidLoad). | |
public extension Promised { | |
@discardableResult | |
func wait() async -> WrappedValue? { | |
return try? await self.value | |
} | |
} | |
// For running result on main thread just use Task with @MainActor, like: | |
// let promise: Promised<Void> = .init() | |
// Task { @MainActor in | |
// await promise.wait() | |
// animate() | |
// } | |
// promise.resolve(with: ()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment