171 lines
4.8 KiB
Swift
171 lines
4.8 KiB
Swift
//
|
|
// Promise.swift
|
|
// SimpleSwiftPromises
|
|
//
|
|
// Created by Shadowfacts on 2/14/20.
|
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public class Promise<Result> {
|
|
private var handlers: [(Result) -> Void] = []
|
|
private var result: Result?
|
|
private var catchers: [(Error) -> Void] = []
|
|
private var error: Error?
|
|
|
|
func resolve(_ result: Result) {
|
|
self.result = result
|
|
self.handlers.forEach { $0(result) }
|
|
}
|
|
|
|
func reject(_ error: Error) {
|
|
self.error = error
|
|
self.catchers.forEach { $0(error) }
|
|
}
|
|
|
|
func addHandler(_ handler: @escaping (Result) -> Void) {
|
|
if let result = result {
|
|
handler(result)
|
|
} else {
|
|
handlers.append(handler)
|
|
}
|
|
}
|
|
|
|
func addCatcher(_ catcher: @escaping (Error) -> Void) {
|
|
if let error = error {
|
|
catcher(error)
|
|
} else {
|
|
catchers.append(catcher)
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension Promise {
|
|
static func resolve<Result>(_ value: Result) -> Promise<Result> {
|
|
let promise = Promise<Result>()
|
|
promise.resolve(value)
|
|
return promise
|
|
}
|
|
|
|
static func reject<Result>(_ error: Error) -> Promise<Result> {
|
|
let promise = Promise<Result>()
|
|
promise.reject(error)
|
|
return promise
|
|
}
|
|
|
|
static func all<Result>(_ promises: [Promise<Result>], queue: DispatchQueue = .main) -> Promise<[Result]> {
|
|
let group = DispatchGroup()
|
|
|
|
var results = [Result?](repeating: nil, count: promises.count)
|
|
var firstError: Error?
|
|
|
|
for (index, promise) in promises.enumerated() {
|
|
group.enter()
|
|
promise.then { (res) in
|
|
queue.async {
|
|
results[index] = res
|
|
group.leave()
|
|
}
|
|
}.catch { (err) -> Void in
|
|
if firstError == nil {
|
|
firstError = err
|
|
}
|
|
group.leave()
|
|
}
|
|
}
|
|
|
|
return Promise<[Result]> { (resolve, reject) in
|
|
group.notify(queue: queue) {
|
|
if let firstError = firstError {
|
|
reject(firstError)
|
|
} else {
|
|
resolve(results.compactMap { $0 })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
convenience init(resultProvider: @escaping (_ resolve: @escaping (Result) -> Void, _ reject: @escaping (Error) -> Void) -> Void) {
|
|
self.init()
|
|
resultProvider(self.resolve, self.reject)
|
|
}
|
|
|
|
convenience init<ErrorType>(_ resultProvider: @escaping ((Swift.Result<Result, ErrorType>) -> Void) -> Void) {
|
|
self.init { (resolve, reject) in
|
|
resultProvider { (result) in
|
|
switch result {
|
|
case let .success(res):
|
|
resolve(res)
|
|
case let .failure(error):
|
|
reject(error)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@discardableResult
|
|
func then(_ func: @escaping (Result) -> Void) -> Promise<Result> {
|
|
addHandler(`func`)
|
|
return self
|
|
}
|
|
|
|
func then<Next>(_ mapper: @escaping (Result) -> Promise<Next>) -> Promise<Next> {
|
|
let next = Promise<Next>()
|
|
addHandler { (parentResult) in
|
|
let newPromise = mapper(parentResult)
|
|
newPromise.addHandler(next.resolve)
|
|
newPromise.addCatcher(next.reject)
|
|
}
|
|
addCatcher(next.reject)
|
|
return next
|
|
}
|
|
|
|
func then<Next>(_ mapper: @escaping (Result) -> Next) -> Promise<Next> {
|
|
let next = Promise<Next>()
|
|
addHandler { (parentResult) in
|
|
let newResult = mapper(parentResult)
|
|
next.resolve(newResult)
|
|
}
|
|
addCatcher(next.reject)
|
|
return next
|
|
}
|
|
|
|
@discardableResult
|
|
func `catch`(_ catcher: @escaping (Error) -> Void) -> Promise<Result> {
|
|
addCatcher(catcher)
|
|
return self
|
|
}
|
|
|
|
func `catch`(_ catcher: @escaping (Error) -> Promise<Result>) -> Promise<Result> {
|
|
let next = Promise<Result>()
|
|
addHandler(next.resolve)
|
|
addCatcher { (error) in
|
|
let newPromise = catcher(error)
|
|
newPromise.addHandler(next.resolve)
|
|
newPromise.addCatcher(next.reject)
|
|
}
|
|
return next
|
|
}
|
|
|
|
func `catch`(_ catcher: @escaping (Error) -> Result) -> Promise<Result> {
|
|
let next = Promise<Result>()
|
|
addHandler(next.resolve)
|
|
addCatcher { (error) in
|
|
let newResult = catcher(error)
|
|
next.resolve(newResult)
|
|
}
|
|
return next
|
|
}
|
|
|
|
func handle(on queue: DispatchQueue) -> Promise<Result> {
|
|
return self.then { (result) in
|
|
return Promise { (resolve, reject) in
|
|
queue.async {
|
|
resolve(result)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|