Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@fmo91
Last active March 9, 2021 07:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fmo91/40fcd72388a5ccab720ab21fdcaebc3f to your computer and use it in GitHub Desktop.
Save fmo91/40fcd72388a5ccab720ab21fdcaebc3f to your computer and use it in GitHub Desktop.
The minimum viable promise in Swift
import Foundation
struct Promise<T> {
typealias ResultType = Result<T, Error>
typealias ResultObserver = (ResultType) -> Void
typealias CreatorFunction = (@escaping ResultObserver) -> Void
private let creatorFunction: CreatorFunction
init(creatorFunction: @escaping CreatorFunction) {
self.creatorFunction = creatorFunction
}
func then<E>(_ f: @escaping (T) -> E) -> Promise<E> {
return Promise<E> { observer in
self.creatorFunction { r in
observer(r.map(f))
}
}
}
static func all(_ promises: [Promise<T>], on queue: DispatchQueue = .main) -> Promise<[T]> {
return Promise<[T]> { observer in
let group = DispatchGroup()
var values = [T]()
var hasFailed = false
for promise in promises {
group.enter()
promise.then { r in
switch r {
case let .success(value):
values.append(value)
case let .failure(error):
observer(.failure(error))
hasFailed = true
}
group.leave()
}
}
group.notify(queue: queue) {
guard !hasFailed else {
return
}
observer(.success(values))
}
}
}
func then<E>(_ f: @escaping (T) -> Promise<E>) -> Promise<E> {
return Promise<E> { observer in
self.creatorFunction { firstResult in
switch firstResult {
case .success(let successResult):
f(successResult).creatorFunction { transformedResult in
observer(transformedResult)
}
case .failure(let error):
observer(.failure(error))
}
}
}
}
@discardableResult func then(_ f: @escaping (ResultType) -> Void) -> Self {
creatorFunction { r in f(r) }
return self
}
}
func getNumber() -> Promise<Int> {
return .init { (observer) in
observer(.success(5))
}
}
func getTextFromNumber(_ number: Int) -> Promise<String> {
return .init { observer in
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
observer(.success("Fernando \(number)"))
}
}
}
getNumber()
.then(getTextFromNumber)
.then { r in
switch r {
case .success(let text):
print(text)
case .failure(let error):
print(error)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment