mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2024-12-10 15:47:02 +01:00
91 lines
2.8 KiB
Swift
91 lines
2.8 KiB
Swift
|
import Combine
|
||
|
|
||
|
// Ref: https://www.swiftbysundell.com/articles/connecting-async-await-with-other-swift-code/
|
||
|
|
||
|
extension Publishers {
|
||
|
public struct MissingOutputError: Error {}
|
||
|
}
|
||
|
|
||
|
extension Publisher {
|
||
|
public func singleOutput() async throws -> Output {
|
||
|
var cancellable: AnyCancellable?
|
||
|
var didReceiveValue = false
|
||
|
|
||
|
return try await withCheckedThrowingContinuation { continuation in
|
||
|
cancellable = sink(
|
||
|
receiveCompletion: { completion in
|
||
|
switch completion {
|
||
|
case .failure(let error):
|
||
|
continuation.resume(throwing: error)
|
||
|
case .finished:
|
||
|
if !didReceiveValue {
|
||
|
continuation.resume(
|
||
|
throwing: Publishers.MissingOutputError()
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
receiveValue: { value in
|
||
|
guard !didReceiveValue else { return }
|
||
|
|
||
|
didReceiveValue = true
|
||
|
cancellable?.cancel()
|
||
|
continuation.resume(returning: value)
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ref: https://www.swiftbysundell.com/articles/calling-async-functions-within-a-combine-pipeline/
|
||
|
|
||
|
extension Publisher {
|
||
|
public func asyncMap<T>(
|
||
|
_ transform: @escaping (Output) async -> T
|
||
|
) -> Publishers.FlatMap<Future<T, Never>, Self> {
|
||
|
flatMap { value in
|
||
|
Future { promise in
|
||
|
Task {
|
||
|
let output = await transform(value)
|
||
|
promise(.success(output))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public func asyncMap<T>(
|
||
|
_ transform: @escaping (Output) async throws -> T
|
||
|
) -> Publishers.FlatMap<Future<T, Error>, Self> {
|
||
|
flatMap { value in
|
||
|
Future { promise in
|
||
|
Task {
|
||
|
do {
|
||
|
let output = try await transform(value)
|
||
|
promise(.success(output))
|
||
|
} catch {
|
||
|
promise(.failure(error))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public func asyncMap<T>(
|
||
|
_ transform: @escaping (Output) async throws -> T
|
||
|
) -> Publishers.FlatMap<Future<T, Error>,
|
||
|
Publishers.SetFailureType<Self, Error>> {
|
||
|
flatMap { value in
|
||
|
Future { promise in
|
||
|
Task {
|
||
|
do {
|
||
|
let output = try await transform(value)
|
||
|
promise(.success(output))
|
||
|
} catch {
|
||
|
promise(.failure(error))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|