<commit_before>//
//  Deferred.swift
//  Deferred
//
//  Created by <NAME> on 3/2/15.
//  Copyright (c) 2015 Remarkable.io. All rights reserved.
//

import Foundation

internal struct Then<T> {
    let onFulfilled: T -> ()
    let onRejected: NSError -> ()
}

public final class Deferred<T> {

    typealias ThenBlock = Then<T>
    private typealias WrappedFulfilledBlock = T -> ()
    public typealias RejectedBlock = NSError -> ()

    /** If `value` is filled then the promise was resolved. */
    private var value: T?

    /** If `error` is filled then the promise was rejected. */
    private var error: NSError?

    /** `ThenBlock` objects whose onFulfilled or onRejected will be called upon `resolve(value: T)` or `reject(error: NSError)`, respectively. */
    internal var pending: [ThenBlock] = [ThenBlock]()

    /** Returns an empty (unresolved, unrejected) promise. */
    public required init() { } // Shouldn't be necessary?

    /** Returns a promise resolved with the given `value`. */
    public convenience init(value: T) {
        self.init()
        self.resolve(value)
    }

    /** Returns a promise rejected with the given `error`. */
    public convenience init(error: NSError) {
        self.init()
        self.reject(error)
    }

    /** Returns a collective promise that resolves with a collection of T when all resolve */
    public class func combine(promises: [Deferred<T>]) -> Deferred<[T]> {
        let combined = Deferred<[T]>()

        var collection = [T]()

        for deferred in promises {
            deferred.then({ value -> Void in
                collection += [value]

                if collection.count == promises.count {
                    combined.resolve(collection)
                }
            })
        }

        return combined
    }

    /** Appends to `pending` a `Then<T>` object containing the given `onFulfilled` and (optional) `onRejected` blocks, or calls onFulfilled/onRejected if the promise is already fulfilled or rejected, respectively. */
    public func then<U>(onFulfilled: (T) -> U, _ onRejected: RejectedBlock = { error in }) -> Deferred<U> {

        // Chained promise to be returned
        let deferred = Deferred<U>()

        // Curry onFulfilled and onRejected before appending ThenBlock to `pending`
        let _onFulfilled = wrapFulfilledBlock(deferred, onFulfilled: onFulfilled)
        let _onRejected = wrapRejectedBlock(deferred, onRejected: onRejected)

        // Check promise status
        if let value = value {

            // Fulfilled, call onFulfilled immediately
            _onFulfilled(value)

        } else if let error = error {

            // Rejected, call onRejected immediately
            _onRejected(error)

        } else {

            // Pending, add ThenBlock
            pending.append(ThenBlock(onFulfilled: _onFulfilled, onRejected: _onRejected))

        }

        return deferred
    }

    public func then<U>(onFulfilled: (T) -> Deferred<U>, _ onRejected: RejectedBlock = { error in }) -> Deferred<U> {

        let temp = Deferred<U>()

        let _onFulfilled: T -> () = { value in
            let next = onFulfilled(value)
            if let nextValue = next.value {
                temp.resolve(nextValue)
            } else if let nextError = next.error {
                temp.reject(nextError)
            } else {
                temp.pending += next.pending
            }
        }

        let _onRejected: NSError -> () = { error in
            temp.reject(error)
        }

        if let value = value {
            _onFulfilled(value)
        } else if let error = error {
            _onRejected(error)
        } else {
            pending += [ThenBlock(onFulfilled: _onFulfilled, onRejected: _onRejected)]
        }

        return temp
    }

    /** Resolve the promise, clearing `pending` after calling each `onFulfilled` block with the given `value`. */
    public func resolve(value: T) {
        // Promise fulfilled, set value<commit_msg>fix failing test case<commit_after>//
//  Deferred.swift
//  Deferred
//
//  Created by <NAME> on 3/2/15.
//  Copyright (c) 2015 Remarkable.io. All rights reserved.
//

import Foundation

internal struct Then<T> {
    let onFulfilled: T -> ()
    let onRejected: NSError -> ()
}

public final class Deferred<T> {

    typealias ThenBlock = Then<T>
    private typealias WrappedFulfilledBlock = T -> ()
    public typealias RejectedBlock = NSError -> ()

    /** If `value` is filled then the promise was resolved. */
    private var value: T?

    /** If `error` is filled then the promise was rejected. */
    private var error: NSError?

    /** `ThenBlock` objects whose onFulfilled or onRejected will be called upon `resolve(value: T)` or `reject(error: NSError)`, respectively. */
    internal var pending: [ThenBlock] = [ThenBlock]()

    /** Returns an empty (unresolved, unrejected) promise. */
    public required init() { } // Shouldn't be necessary?

    /** Returns a promise resolved with the given `value`. */
    public convenience init(value: T) {
        self.init()
        self.resolve(value)
    }

    /** Returns a promise rejected with the given `error`. */
    public convenience init(error: NSError) {
        self.init()
        self.reject(error)
    }

    /** Returns a collective promise that resolves with a collection of T when all resolve */
    public class func combine(promises: [Deferred<T>]) -> Deferred<[T]> {
        let combined = Deferred<[T]>()

        var collection = [T]()

        for deferred in promises {
            deferred.then({ value -> Void in
                collection += [value]

                if collection.count == promises.count {
                    combined.resolve(collection)
                }
            })
        }

        return combined
    }

    /** Appends to `pending` a `Then<T>` object containing the given `onFulfilled` and (optional) `onRejected` blocks, or calls onFulfilled/onRejected if the promise is already fulfilled or rejected, respectively. */
    public func then<U>(onFulfilled: (T) -> U, _ onRejected: RejectedBlock = { error in }) -> Deferred<U> {

        // Chained promise to be returned
        let deferred = Deferred<U>()

        // Curry onFulfilled and onRejected before appending ThenBlock to `pending`
        let _onFulfilled = wrapFulfilledBlock(deferred, onFulfilled: onFulfilled)
        let _onRejected = wrapRejectedBlock(deferred, onRejected: onRejected)

        // Check promise status
        if let value = value {

            // Fulfilled, call onFulfilled immediately
            _onFulfilled(value)

        } else if let error = error {

            // Rejected, call onRejected immediately
            _onRejected(error)

        } else {

            // Pending, add ThenBlock
            pending.append(ThenBlock(onFulfilled: _onFulfilled, onRejected: _onRejected))

        }

        return deferred
    }

    public func then<U>(onFulfilled: (T) -> Deferred<U>, _ onRejected: RejectedBlock = { error in }) -> Deferred<U> {

        // Proxy since we won't have a Deferred<U> until self resolves
        let proxy = Deferred<U>()

        // When self resolves, add then block to resulting Deferred<U>
        let _onFulfilled: T -> () = { value in

            let next = onFulfilled(value)

            next.then({ value in
                proxy.resolve(value)
            }, { error in
                proxy.reject(error)
            })

        }

        // When self rejects, reject proxy with error
        let _onRejected: NSError -> () = { error in
            proxy.reject(error)
        }

        then(_onFulfilled, _onRejected)

        return proxy
    }

    /** Resolve the promise, clearing `pending` after calling each `onFulfilled` block with the given `value`. */
    public func resolve(value: T) {
        // Promise fulfilled, set value
{'fraction_non_alphanumeric': 0.10442837203400583, 'fraction_numerical': 0.0020301992132978047, 'mean_word_length': 2.1477635782747604, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4001867', 'n_tokens_mistral': 2348, 'n_tokens_neox': 2179, 'n_words': 700}