TM-SGNL-iOS/SignalServiceKit/PromiseKit/Thenable.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

82 lines
2.1 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol Thenable: AnyObject {
associatedtype Value
var result: Result<Value, Error>? { get }
init()
func observe(on scheduler: Scheduler?, block: @escaping (Result<Value, Error>) -> Void)
}
public extension Thenable {
func map<T>(
on scheduler: Scheduler? = nil,
_ block: @escaping (Value) throws -> T
) -> Promise<T> {
observe(on: scheduler, block: block)
}
func done(
on queue: Scheduler? = nil,
_ block: @escaping (Value) throws -> Void
) -> Promise<Void> {
observe(on: queue, block: block)
}
func then<T: Thenable>(
on scheduler: Scheduler? = nil,
_ block: @escaping (Value) throws -> T
) -> Promise<T.Value> {
let (promise, future) = Promise<T.Value>.pending()
observe(on: scheduler) { result in
do {
switch result {
case .success(let value):
future.resolve(on: scheduler, with: try block(value))
case .failure(let error):
future.reject(error)
}
} catch {
future.reject(error)
}
}
return promise
}
var value: Value? {
guard case .success(let value) = result else { return nil }
return value
}
func asVoid(
on scheduler: Scheduler? = nil
) -> Promise<Void> {
map(on: scheduler) { _ in }
}
}
fileprivate extension Thenable {
func observe<T>(
on scheduler: Scheduler?,
block: @escaping (Value) throws -> T
) -> Promise<T> {
let (promise, future) = Promise<T>.pending()
observe(on: scheduler) { result in
do {
switch result {
case .success(let value):
future.resolve(try block(value))
case .failure(let error):
future.reject(error)
}
} catch {
future.reject(error)
}
}
return promise
}
}