Skip to content

Instantly share code, notes, and snippets.

@ashikahmad
Created February 14, 2019 15:07
Show Gist options
  • Save ashikahmad/0661f38bd3f78c35bcf829ce9b6f3b4b to your computer and use it in GitHub Desktop.
Save ashikahmad/0661f38bd3f78c35bcf829ce9b6f3b4b to your computer and use it in GitHub Desktop.
import UIKit
import PlaygroundSupport
extension String: Error {}
func getEvenNumber() -> Future<Int> {
return Future<Int>.create { p in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let num = Int.random(in: 0...20)
if num % 2 == 0 {
p.fulfill(with: num)
} else {
p.reject(with: "\(num) - Not Even")
}
}
}
}
// ----[ USAGE ]------------------------
PlaygroundPage.current.needsIndefiniteExecution = true
getEvenNumber()
.chain { num -> Future<String> in
return Future<String>.create { p in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
p.fulfill(with: "-- \(num) --")
})
}
}.map { str -> Int in
print(str)
let num = str.count
if num == 8 { throw "Two Digit" }
return num
}.onCompletion { val in
print("Value:", val)
}.onError { err in
print("Error:", err)
}.finally {
print("Finish!")
}
/*
* Promise.swift
* -----------------------------------------------------------
* Project : Promise (Playground)
* Created on : 14 Feb, 2019
* Created by : Ashik uddin Ahmad (ashik.u.ahmad@gmail.com)
* -----------------------------------------------------------
* Copyright © 2018 Ashik uddin Ahmad. All rights reserved.
*/
import Foundation
// -----------------------------------------------------------
// MARK: - Result
// -----------------------------------------------------------
fileprivate enum Result<V> {
case success(V)
case failure(Error)
}
// -----------------------------------------------------------
// MARK: - Future
// -----------------------------------------------------------
public class Future<V> {
fileprivate var _result: Result<V>? {
didSet { broadcast() }
}
private lazy var completions: [((Result<V>)->Void)] = []
private func broadcast() {
if let r = _result {
for completion in completions {
completion(r)
}
}
}
fileprivate func observe(_ closure: @escaping (Result<V>)->Void) {
completions.append(closure)
if let r = _result {
closure(r)
}
}
}
// -----------------------------------------------------------
// MARK: - Promise
// -----------------------------------------------------------
public class Promise<V>: Future<V> {
public func fulfill(with value: V) {
_result = .success(value)
}
public func reject(with error: Error) {
_result = .failure(error)
}
}
// -----------------------------------------------------------
// MARK: - Future - Observing
// -----------------------------------------------------------
public extension Future {
public func onCompletion(_ closure: @escaping (V)->Void) -> Future<V> {
observe { result in
if case let .success(val) = result {
closure(val)
}
}
return self
}
public func onError(_ closure: @escaping (Error)->Void) -> Future<V> {
observe { result in
if case let .failure(err) = result {
closure(err)
}
}
return self
}
public func finally(_ closure: @escaping ()->Void) {
observe { _ in
closure()
}
}
}
// -----------------------------------------------------------
// MARK: - Future - Building
// -----------------------------------------------------------
public extension Future {
public static func create(_ builder: (Promise<V>)->Void)->Future<V> {
let p = Promise<V>()
builder(p)
return p
}
}
// -----------------------------------------------------------
// MARK: - Future - Chaining & Transformation
// -----------------------------------------------------------
public extension Future {
public func chain<U>(_ transform: @escaping (V) throws ->Future<U>)->Future<U> {
return Future<U>.create { p in
self.observe { result in
switch result {
case .success(let val):
do {
let p2 = try transform(val)
p2.observe { r in
switch r {
case .success(let v):
p.fulfill(with: v)
case .failure(let e):
p.reject(with: e)
}
}
} catch {
p.reject(with: error)
}
case .failure(let err):
p.reject(with: err)
}
}
}
}
public func map<U>(_ transform: @escaping (V) throws ->U)->Future<U> {
return Future<U>.create { p in
self.observe { result in
switch result {
case .success(let val):
do {
let v2 = try transform(val)
p.fulfill(with: v2)
} catch {
p.reject(with: error)
}
case .failure(let err):
p.reject(with: err)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment