<commit_before>// Signal.swift
//
// Copyright (c) 2015 <NAME> (http://jensravens.de)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/**
    A Signal is value that will or will not contain a value in the future (just
    like the concept of futures). In contrast to futures, the value of a signal
    can change at any time.

    Use next to subscribe to .Success updates, .error for .Error updates and 
    update to update the current value of the signal.

        let text = Signal<String>()

        text.next { string in
            println("Hello \(string)")
        }

        text.update(.Success("World"))

*/
import Foundation

public final class Signal<T> {
    
    private var value: Result<T>?
    private var callbacks: [Result<T> -> Void] = []
    
    /// Automatically infer the type of the signal from the argument.
    public convenience init(_ value: T){
        self.init()
        self.value = .Success(value)
    }
    
    public init() {
        
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func map<U>(f: T -> U) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.map(f))
        }
        return signal
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: T -> Result<U>) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.flatMap(f))
        }
        return signal
    }
    
    /**
    Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: T throws -> U) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.flatMap(f))
        }
        return signal
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: (T, (Result<U>->Void))->Void) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            result.flatMap(f)(signal.update)
        }
        return signal
    }
    
    /**
        Call a function with the result as an argument. Use this if the function should be
        executed no matter if the signal is a success or not.
        This method can also be used to convert an .Error into a .Success which might be handy
        for retry logic.
    */
    public func ensure<U>(f: (Result<T>, (Result<U>->Void))->Void) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            f(result) { signal.update($0) }
        }
        return signal
    }
    
    /**
        Subscribe to the changes of this signal (.Error and .Success).<commit_msg>Add flatMap implementation where ( T -> Signal<U> ) -> Signal <U><commit_after>// Signal.swift
//
// Copyright (c) 2015 <NAME> (http://jensravens.de)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/**
    A Signal is value that will or will not contain a value in the future (just
    like the concept of futures). In contrast to futures, the value of a signal
    can change at any time.

    Use next to subscribe to .Success updates, .error for .Error updates and 
    update to update the current value of the signal.

        let text = Signal<String>()

        text.next { string in
            println("Hello \(string)")
        }

        text.update(.Success("World"))

*/
import Foundation

public final class Signal<T> {
    
    private var value: Result<T>?
    private var callbacks: [Result<T> -> Void] = []
    
    /// Automatically infer the type of the signal from the argument.
    public convenience init(_ value: T){
        self.init()
        self.value = .Success(value)
    }
    
    public init() {
        
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func map<U>(f: T -> U) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.map(f))
        }
        return signal
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: T -> Result<U>) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.flatMap(f))
        }
        return signal
    }
    
    /**
    Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: T throws -> U) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            signal.update(result.flatMap(f))
        }
        return signal
    }
    
    /**
        Transform the signal into another signal using a function.
    */
    public func flatMap<U>(f: (T, (Result<U>->Void))->Void) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            result.flatMap(f)(signal.update)
        }
        return signal
    }
    
    /**
        Transform the signal into another signal using a function, return the
        value of the inner signal
    */
    public func flatMap<U>(f: (T -> Signal<U>)) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            switch(result) {
            case let .Success(value):
                let innerSignal = f(value)
                innerSignal.subscribe { innerResult in
                    signal.update(innerResult)
                }
            case let .Error(error):
                signal.update(.Error(error))
            }
        }
        return signal
    }
    
    /**
        Call a function with the result as an argument. Use this if the function should be
        executed no matter if the signal is a success or not.
        This method can also be used to convert an .Error into a .Success which might be handy
        for retry logic.
    */
    public func ensure<U>(f: (Result<T>, (Result<U>->Void))->Void) -> Signal<U> {
        let signal = Signal<U>()
        subscribe { result in
            f(result) { signal.update($0) }
        }
        return signal
    }
    
    /**
        Subscribe to the changes of this signal (.Error and .Success).
{'fraction_non_alphanumeric': 0.09555528642364054, 'fraction_numerical': 0.0012110936175366357, 'mean_word_length': 2.1375379939209727, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 87, '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': '7179395', 'n_tokens_mistral': 2251, 'n_tokens_neox': 2135, 'n_words': 929}