Skip to content

Instantly share code, notes, and snippets.

@toruuetani
Created May 17, 2016 08:01
Show Gist options
  • Save toruuetani/47c9931717943e183edd52215d72f91d to your computer and use it in GitHub Desktop.
Save toruuetani/47c9931717943e183edd52215d72f91d to your computer and use it in GitHub Desktop.
//
// Promise.swift
// TestApp
//
// Created by toruuetani on 2016/05/17.
// Copyright © 2016年 ryoden. All rights reserved.
//
import Foundation
enum PromiseState {
case Pending
case Fulfilled
case Rejected
}
enum PromiseResult<T> {
case Undefined
case Value(T)
case Error(ErrorType)
}
final class Promise<T> {
internal private(set) var state: PromiseState = .Pending {
didSet {
if oldValue == self.state { return }
if oldValue != PromiseState.Pending { return }
switch (self.state, self.result) {
case (.Fulfilled, .Value(let value)):
self.resolve?(value)
case (.Rejected, .Error(let error)):
self.reject?(error)
default:
break
}
}
}
private(set) var result: PromiseResult<T> = .Undefined
private(set) var resolve: (T -> Void)?
private(set) var reject: (ErrorType -> Void)?
init(_ executor: (T -> Void, ErrorType -> Void) -> Void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
executor(self.onFulfilled, self.onRejected)
})
}
private func onFulfilled(data: T) {
if self.state != .Pending { return }
self.result = .Value(data)
self.state = .Fulfilled
}
private func onRejected(error: ErrorType) {
if self.state != .Pending { return }
self.result = .Error(error)
self.state = .Rejected
}
func error(onRejected: ErrorType -> Void) -> Promise<T> {
return self.then({ $0 }, onRejected)
}
func then<U>(onFulfilled: T -> U) -> Promise<U> {
return self.then(onFulfilled, nil)
}
func then<U>(onFulfilled: T -> U, _ onRejected: (ErrorType -> Void)?) -> Promise<U> {
return Promise<U> { _resolve, _reject in
switch (self.state, self.result) {
case (.Pending, _):
let resolve = self.resolve
self.resolve = {
resolve?($0)
_resolve(onFulfilled($0))
}
let reject = self.reject
self.reject = {
reject?($0)
_reject($0)
onRejected?($0)
}
case (.Fulfilled, .Value(let value)):
_resolve(onFulfilled(value))
case (.Rejected, .Error(let error)):
_reject(error)
onRejected?(error)
default:
assertionFailure()
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment