<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 <NAME> (github.com/kean).

import Foundation

/// A promise is an object that represents an asynchronous task. Use `then()`
/// to get the result of the promise. Use `catch()` to catch errors.
///
/// Promises start in a *pending* state and *resolve* with a value to become
/// *fulfilled* or an `Error` to become *rejected*.
public final class Promise<T> {
    // Promise is built into Nuke to avoid fetching external dependencies.

    private var state: PromiseState<T> = .pending(PromiseHandlers<T>())
    private let lock = Lock()

    /// Creates a new, pending promise.
    ///
    /// - parameter value: The provided closure is called immediately on the
    /// current thread. In the closure you should start an asynchronous task and
    /// call either `fulfill` or `reject` when it completes.
    public init(_ closure: (_ fulfill: @escaping (T) -> Void, _ reject: @escaping (Error) -> Void) -> Void) {
        closure({ self.resolve(.fulfilled($0)) }, { self.resolve(.rejected($0)) })
    }

    /// Creates a promise fulfilled with a given value.
    public init(value: T) {
        state = .resolved(.fulfilled(value))
    }

    /// Create a promise rejected with a given error.
    public init(error: Error) {
        state = .resolved(.rejected(error))
    }

    private func resolve(_ resolution: PromiseResolution<T>) {
        lock.lock()
        if case let .pending(handlers) = state {
            state = .resolved(resolution)
            handlers.objects.forEach { $0(resolution) }
        }
        lock.unlock()
    }

    /// The provided closure executes asynchronously when the promise resolves.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    /// - returns: self
    @discardableResult public func completion(on queue: DispatchQueue = .main, _ closure: @escaping (PromiseResolution<T>) -> Void) -> Promise {
        let completion: (PromiseResolution<T>) -> Void = { resolution in
            queue.async { closure(resolution) }
        }
        lock.lock()
        switch state {
        case let .pending(handlers): handlers.objects.append(completion)
        case let .resolved(resolution): completion(resolution)
        }
        lock.unlock()
        return self
    }

    // MARK: Properties

    /// Returns `true` if the promise is still pending.
    public var isPending: Bool {
        return resolution == nil
    }

    /// Returns resolution if the promise has already resolved.
    public var resolution: PromiseResolution<T>? {
        return lock.sync { state.resolution }
    }
}

public extension Promise {

    /// The provided closure executes asynchronously when the promise fulfills
    /// with a value. Allows to add a handler without breaking the chain.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    /// - returns: self
    @discardableResult public func then(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> Void) -> Promise {
        return completion(on: queue, fulfill: closure, reject: nil)
    }

    /// The provided closure executes asynchronously when the promise fulfills
    /// with a value. Allows to transform `Promise<T>` to `Promise<U>`.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    /// queue by default.
    /// - returns: A promise fulfilled with a value returns by the closure.
    public func then<U>(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> U) -> Promise<U> {
        return then(on: queue) { Promise<U>(value: closure($0)) }
    }
    
    /// The provided closure executes asynchronously when the promise fulfills
    /// with a value. Allows to chain promises.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    /// - returns: A promise that resolves with the resolution of the promise
    /// returned by the given closure.
    public func then<U>(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> Promise<U>) -> Promise<U> {
        return Promise<U>() { fulfill, reject in
            completion(
                on: queue,
                fulfill: { // resolve new promise with the promise returned by the closure
                    closure($0).completion(on: queue, fulfill: fulfill, reject: reject)
                },
                reject: reject) // bubble up error
        }
    }

    /// The provided closure executes asynchronously when the promise is
    /// rejected with an error.
    ///
    /// A promise bubbles up errors. It allows you to catch all errors returned
    /// by a chain of promises with a single `catch()`.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    @discardableResult public func `catch`(on queue: DispatchQueue = .main, _ closure: @escaping (Error) -> Void) {
        completion(on: queue, fulfill: nil, reject: closure)
    }

    /// Unlike `catch` `recover` allows you to continue the chain of promises
    /// by recovering from the error by creating a new promise.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    public func recover(on queue: DispatchQueue = .main, _ closure: @escaping (Error) -> Promise) -> Promise {
        return Promise() { fulfill, reject in
            completion(
                on: queue,
                fulfill: fulfill, // bubble up value
                reject: { // resolve new promise with the promise returned by the closure
                    closure($0).completion(on: queue, fulfill: fulfill, reject: reject)
            })
        }
    }

    /// Private convenience method on top of `completion(on:closure:)`.
    @discardableResult private func completion(on queue: DispatchQueue = .main, fulfill: ((T) -> Void)?, reject: ((Error) -> Void)?) -> Promise {
        return completion(on: queue) {
            switch $0 {
            case let .fulfilled(val): fulfill?(val)
            case let .rejected(err): reject?(err)
            }
        }
    }

    @available(*, deprecated: 4.2, message: "Use completion() instead which now also returns a Promise")
    @discardableResult public func then(on queue: DispatchQueue = .main, fulfilment: ((T) -> Void)?, rejection: ((Error) -> Void)?) -> Promise {
        return completion(on: queue, fulfill: fulfilment, reject: rejection)
    }
}

// FIXME: make nested type when compiler adds support for it
private final class PromiseHandlers<T> {
    var objects = [(PromiseResolution<T>) -> Void]()
}

private enum PromiseState<T> {
    case pending(PromiseHandlers<T>), resolved(PromiseResolution<T>)

    var resolution: PromiseResolution<T>? {
        if case let .resolved(resolution) = self { return resolution }
        return nil
    }
}

/// Represents a *resolution* (result) of a promise.
public enum PromiseResolution<T> {
    case fulfilled(T), rejected(Error)

    public var value: T? {
        if case let .fulfilled(val) = self { return val }
        return nil
    }

    public var error: Error? {
        if case let .rejected(err) = self { return err }
        return nil
    }
}<commit_msg>Bring improvements made in Pill.Promise<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 <NAME> (github.com/kean).

import Foundation

/// A promise represents a value which may be available now, or in the future,
/// or never. Use `then()` to get the result of the promise. Use `catch()`
/// to catch errors.
///
/// Promises start in a *pending* state and *resolve* with a value to become
/// *fulfilled* or an `Error` to become *rejected*.
///
/// This `Nuke.Promise` is a variant of [Pill.Promise](https://github.com/kean/Pill)
/// with simplified APIs (adds `completion`, doesn't allow `throws`, etc).
/// The `Promise` is built into Nuke to avoid fetching external dependencies.
public final class Promise<T> {
    private var state: PromiseState<T> = .pending(PromiseHandlers<T>())
    private let lock = Lock()

    /// Creates a new, pending promise.
    ///
    /// - parameter closure: The closure is called immediately on the current
    /// thread. You should start an asynchronous task and call either `fulfill`
    /// or `reject` when it completes.
    public init(_ closure: (_ fulfill: @escaping (T) -> Void, _ reject: @escaping (Error) -> Void) -> Void) {
        closure({ self._resolve(.fulfilled($0)) }, { self._resolve(.rejected($0)) })
    }

    /// Creates a promise fulfilled with a given value.
    public init(value: T) { state = .resolved(.fulfilled(value)) }

    /// Create a promise rejected with a given error.
    public init(error: Error) { state = .resolved(.rejected(error)) }

    private func _resolve(_ resolution: PromiseResolution<T>) {
        lock.lock(); defer { lock.unlock() }
        if case let .pending(handlers) = state {
            state = .resolved(resolution)
            handlers.objects.forEach { $0(resolution) }
        }
    }
    
    // MARK: Callbacks
    
    private func _observe(on queue: DispatchQueue = .main, _ closure: @escaping (PromiseResolution<T>) -> Void) {
        let _closure: (PromiseResolution<T>) -> Void = { res in queue.async { closure(res) } }
        
        // Handlers only contain `queue.async` calls which are fast
        // enough for a critical section (no real need to optimize this).
        lock.lock(); defer { lock.unlock() }
        switch state {
        case let .pending(handlers): handlers.objects.append(_closure)
        case let .resolved(resolution): _closure(resolution)
        }
    }
    
    private func _observe(on queue: DispatchQueue = .main, fulfill: ((T) -> Void)?, reject: ((Error) -> Void)?) {
        _observe(on: queue) {
            switch $0 {
            case let .fulfilled(val): fulfill?(val)
            case let .rejected(err): reject?(err)
            }
        }
    }
    
    // MARK: Completion
    
    /// The given closure executes asynchronously when the promise resolves.
    ///
    /// - parameter on: A queue on which the closure is executed. `.main` by default.
    /// - returns: self
    @discardableResult public func completion(on queue: DispatchQueue = .main, _ closure: @escaping (PromiseResolution<T>) -> Void) -> Promise {
        _observe(on: queue, closure)
        return self
    }
    
    // MARK: Then

    /// The given closures executes asynchronously when the promise resolves.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    /// - returns: self
    @discardableResult public func then(on queue: DispatchQueue = .main, fulfilment: ((T) -> Void)?, rejection: ((Error) -> Void)?) -> Promise<T> {
        _observe(on: queue, fulfill: fulfilment, reject: rejection)
        return self
    }
    
    /// The given closure executes asynchronously when the promise is fulfilled.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    /// - returns: self
    @discardableResult public func then(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> Void) -> Promise<T> {
        return then(on: queue, fulfilment: closure, rejection: nil)
    }
    
    /// The given closure executes asynchronously when the promise is fulfilled.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    /// - returns: A promise fulfilled with a value returned by the closure.
    @discardableResult public func then<U>(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> U) -> Promise<U> {
        return _then(on: queue) { value, fulfill, _ in
            fulfill(closure(value))
        }
    }
    
    /// The given closure executes asynchronously when the promise is fulfilled.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    /// - returns: A promise that resolves by the promise returned by the closure.
    @discardableResult public func then<U>(on queue: DispatchQueue = .main, _ closure: @escaping (T) -> Promise<U>) -> Promise<U> {
        return _then(on: queue) { value, fulfill, reject in
            closure(value)._observe(on: queue, fulfill: fulfill, reject: reject)
        }
    }
    
    /// Returns a new promise.
    /// - when `self` is fufilled the closure is called (you control it)
    /// - when `self` is rejected the promise is rejected
    private func _then<U>(on queue: DispatchQueue, _ closure: @escaping (T, @escaping (U) -> Void, @escaping (Error) -> Void) -> Void) -> Promise<U> {
        return Promise<U>() { fulfill, reject in
            _observe(on: queue, fulfill: { closure($0, fulfill, reject) }, reject: reject)
        }
    }
    
    // MARK: Catch

    /// The given closure executes asynchronously when the promise is rejected.
    ///
    /// A promise bubbles up errors. It allows you to catch all errors returned
    /// by a chain of promises with a single `catch()`.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    @discardableResult public func `catch`(on queue: DispatchQueue = .main, _ closure: @escaping (Error) -> Void) -> Promise<T> {
        return then(on: queue, fulfilment: nil, rejection: closure)
    }
    
    /// Unlike `catch` `recover` allows you to continue the chain of promises
    /// by recovering from the error by creating a new promise.
    ///
    /// - parameter on: A queue on which the closure is run. `.main` by default.
    /// - returns: A promise that resolves by the promise returned by the closure.
    @discardableResult public func recover(on queue: DispatchQueue = .main, _ closure: @escaping (Error) -> Promise<T>) -> Promise<T> {
        return _catch(on: queue) { error, fulfill, reject in
            closure(error)._observe(on: queue, fulfill: fulfill, reject: reject)
        }
    }
    
    /// Returns a new promise.
    /// - when `self` is fufilled the promise is fulfilled
    /// - when `self` is rejected the closure is called (you control it)
    private func _catch(on queue: DispatchQueue, _ closure: @escaping (Error, @escaping (T) -> Void, @escaping (Error) -> Void) -> Void) -> Promise<T> {
        return Promise<T>() { fulfill, reject in
            _observe(on: queue, fulfill: fulfill, reject: { closure($0, fulfill, reject) })
        }
    }
    
    // MARK: Synchronous Inspection
    
    /// Returns `true` if the promise is still pending.
    public var isPending: Bool { return resolution == nil }
    
    /// Returns resolution if the promise has already resolved.
    public var resolution: PromiseResolution<T>? { return lock.sync { state.resolution } }
}

private final class PromiseHandlers<T> {
    var objects = [(PromiseResolution<T>) -> Void]() // boxed closures
}

private enum PromiseState<T> {
    case pending(PromiseHandlers<T>), resolved(PromiseResolution<T>)

    var resolution: PromiseResolution<T>? {
        if case let .resolved(res) = self { return res } else { return nil }
    }
}

/// Represents a *resolution* (result) of a promise.
public enum PromiseResolution<T> {
    case fulfilled(T), rejected(Error)

    /// Returns the `value` which promise was `fulfilled` with.
    public var value: T? {
        if case let .fulfilled(val) = self { return val } else { return nil }
    }

    /// Returns the `error` which promise was `rejected` with.
    public var error: Error? {
        if case let .rejected(err) = self { return err } else { return nil }
    }
}
{'fraction_non_alphanumeric': 0.12091166623744527, 'fraction_numerical': 0.0014808138037599795, 'mean_word_length': 2.456386292834891, 'pattern_counts': {'":': 0, '<': 58, '<?xml version=': 0, '>': 111, 'https://': 1, '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': '5408860', 'n_tokens_mistral': 4413, 'n_tokens_neox': 4210, 'n_words': 1628}