// // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public protocol Thenable: AnyObject { associatedtype Value var result: Result? { get } init() func observe(on scheduler: Scheduler?, block: @escaping (Result) -> Void) } public extension Thenable { func map( on scheduler: Scheduler? = nil, _ block: @escaping (Value) throws -> T ) -> Promise { observe(on: scheduler, block: block) } func done( on queue: Scheduler? = nil, _ block: @escaping (Value) throws -> Void ) -> Promise { observe(on: queue, block: block) } func then( on scheduler: Scheduler? = nil, _ block: @escaping (Value) throws -> T ) -> Promise { let (promise, future) = Promise.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 { map(on: scheduler) { _ in } } } fileprivate extension Thenable { func observe( on scheduler: Scheduler?, block: @escaping (Value) throws -> T ) -> Promise { let (promise, future) = Promise.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 } }