SwiftでPromiseを作る(async・awaitも作る)

最近JSを初めまして、Promise・async・awaitに惚れました。
なのでホームフィールであるSwiftにこれを持ち込みたい！！！と思いで再実装を行ってみました。Promiseの理解の良い助けにもなりました。

今回は非同期の仕組みは実装せずcallback -> Promiseの変換ができるものを目指します。


# Promiseを作る

まずPromiseの特徴として状態を内部に持つことがあるので`State`を作り、状態を保持しておきます。

```swift
class Promise<Output> {
    enum State {
        case pending
        case fulfilled(Output)
        case rejected(Error)
    }

    var state = State.pending
}
```

また`fullfill`と`reject`をそれぞれできるようにしておきます。


```swift
func fullfill(_ output: Output) {
    self.state = .fulfilled(output)
}
func reject(_ error: Error) {
    self.state = .rejected(error)
}
```

ここまでできたらイニシャライザを実装します。

```swift
init(_ handler: (@escaping (Output)->(), @escaping (Error)->())->()) {
    handler(self.fullfill, self.reject)
}
```

ここまでで状態を持ちfullfill or rejectできるPromiseの仕組みは完成です。
次に、JSのPromiseにおけるthenを実装していきます。


# thenを受け取る


登録されたクロージャを保持しておくために、subscribeできるようにします。

```swift
class Promise {
    struct Subscriber {
        let resolve: (Output)->()
        let reject: (Failure)->()
    }

    var subscribers = [Subscriber]()

    func subscribe(_ resolve: @escaping (Output)->(), _ reject: @escaping (Failure)->()) {
        switch self.state {
        case .pending: 
            let subscriber = Subscriber(resolve: resolve, reject: reject)
            self.subscribers.append(subscriber)
        case .fulfilled(let output): resolve(output)
        case .rejected(let error): reject(error)
        }
    }
}
```

また、fullfillとrejectもsubscribeされたクロージャを実行するように、変更しましょう。


```swift
func fullfill(_ output: Output) {
    self.state = .fulfilled(output)
    for subscriber in subscribers { 
        subscriber.resolve(output) 
    }
    self.subscribers = []
}
func reject(_ error: Error) {
    self.state = .rejected(error)
    for subscriber in subscribers {
        subscriber.reject(error) 
    }
    self.subscribers = []
}
```

これで購読が可能になりました。
メソッドチェーンで購読できるように`extension`を追加してみましょう。

JSのthenはSwiftにおけるmap・flatMap・sinkの機能を同時に持っているので、これらを分けて考えます。


```swift
// Promiseのextension

func map<T>(_ tranceform: @escaping (Output)->T) -> Promise<T> {
    Promise<T> { resolve, reject in
        self.subscribe({ resolve(tranceform($0)) }, reject)
    }
}

func flatMap<T>(_ tranceform: @escaping (Output)->Promise<T>) -> Promise<T> {
    Promise<T> { resolve, reject in
        self.subscribe({ tranceform($0).sink(resolve, reject) }, reject)
    }
}

func sink(_ onFulfilled: @escaping (Output)->(), _ onRejected: @escaping (Error)->()) {
    self.subscribe(onFulfilled, onRejected)
}
```

またJSのcatchはSwiftのreplaceError相当なのでこれも実装しましょう。
(厳密にはreplaceError + map)

```swift
func replaceError(_ tranceform: @escaping (Error)->Output) -> Promise<Output> {
    Promise<Output> { resolve, _ in
        self.subscribe(resolve, { resolve(tranceform($0)) })
    }
}
```

完成！！！！！

```swift
Promise<String>{ resolve, _ in
    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
        resolve("Hello World")
    }
}
.sink{ print($0) } // Hello World
```


async・await→（ちょっとお待ちを）


#全体

```swift
public final class Promise<Output, Failure: Error> {
    private enum State {
        case pending
        case fulfilled(Output)
        case rejected(Failure)
    }
    private struct Subscriber {
        let resolve: (Output)->()
        let reject: (Failure)->()
    }
    
    private var state = State.pending
    private var subscribers = [Subscriber]()
    
    public init(_ handler: (@escaping (Output)->(), @escaping (Failure)->())->()) {
        handler(fullfill, reject)
    }
    
    private func subscribe(_ resolve: @escaping (Output)->(), _ reject: @escaping (Failure)->()) {
        switch self.state {
        case .pending: self.subscribers.append(Subscriber(resolve: resolve, reject: reject))
        case .fulfilled(let output): resolve(output)
        case .rejected(let error): reject(error)
        }
    }
    private func fullfill(_ output: Output) {
        self.state = .fulfilled(output)
        for subscriber in subscribers { subscriber.resolve(output) }
        self.subscribers = []
    }
    private func reject(_ error: Failure) {
        self.state = .rejected(error)
        for subscriber in subscribers { subscriber.reject(error) }
        self.subscribers = []
    }
}

extension Promise {
    public static func resolve(_ output: Output) -> Promise<Output, Never> where Failure == Never {
        Promise<Output, Never> { resolve, _ in resolve(output) }
    }
    
    public static func resolve(_ handler: (@escaping (Output)->())->()) -> Promise<Output, Never> where Failure == Never {
        Promise<Output, Never> { resolve, _ in handler(resolve) }
    }
    
    public static func reject(_ error: Failure) -> Promise<Void, Failure> where Output == Void {
        Promise<Void, Failure> { _, reject in reject(error) }
    }
    
    public static func reject(_ handler: (@escaping (Failure)->())->()) -> Promise<Void, Failure> where Output == Void {
        Promise<Void, Failure> { _, reject in handler(reject) }
    }
}

extension Promise {
    public func map<T>(_ tranceform: @escaping (Output)->T) -> Promise<T, Failure> {
        Promise<T, Failure> { resolve, reject in
            self.subscribe({ resolve(tranceform($0)) }, reject)
        }
    }
    
    public func flatMap<T>(_ tranceform: @escaping (Output)->Promise<T, Failure>) -> Promise<T, Failure> {
        Promise<T, Failure> { resolve, reject in
            self.subscribe({ tranceform($0).sink(resolve, reject) }, reject)
        }
    }
    
    public func mapError<T>(_ tranceform: @escaping (Failure)->T) -> Promise<Output, T> {
        Promise<Output, T> { resolve, reject in
            self.subscribe(resolve, { reject(tranceform($0)) })
        }
    }
        
    public func replaceError(_ tranceform: @escaping (Failure)->Output) -> Promise<Output, Never> {
        Promise<Output, Never> { resolve, _ in
            self.subscribe(resolve, { resolve(tranceform($0)) })
        }
    }
    
    public func `catch`(_ onRejected: @escaping (Error)->()) -> Promise<Void, Never> {
        Promise<Void, Never> { resolve, _ in
            self.subscribe({_ in resolve(()) }, onRejected)
        }
    }
    
    public func sink(_ onFulfilled: @escaping (Output)->(), _ onRejected: @escaping (Failure)->()) {
        self.subscribe(onFulfilled, onRejected)
    }
    
    public func sink(_ onFulfilled: @escaping (Output)->()) where Failure == Never {
        self.subscribe(onFulfilled, {_ in})
    }
}
```