<commit_before>//
//  SignalProducer.swift
//  Edge
//
//  Created by <NAME> on 5/29/16.
//
//

import Foundation

public final class ColdSignal<Value, ErrorType: Error>: ColdSignalType, InternalSignalType, SpecialSignalGenerator {
    internal var observers = Bag<Observer<Value, ErrorType>>()
    
    public var coldSignal: ColdSignal {
        return self
    }
    
    public var signal: Signal<Value, ErrorType> {
        return self.identity
    }
    
    internal let startHandler: (Observer<Value, ErrorType>) -> Disposable?
    
    private var cancelDisposable: Disposable?
    
    private var handlerDisposable: Disposable?
    
    private var started = false
    
    /// Initializes a ColdSignal that will invoke the given closure at the
    /// invocation of `start()`.
    ///
    /// The events that the closure puts into the given observer will become
    /// the events sent to this ColdSignal.
    ///
    /// In order to stop or dispose of the signal, invoke `stop()`. Calling this method
    /// will dispose of the disposable returned by the given closure.
    /// 
    /// Invoking `start()` will have no effect until the signal is stopped. After
    /// `stop()` is called this process may be repeated.
    public init(_ generator: @escaping (Observer<Value, ErrorType>) -> Disposable?) {
        self.startHandler = generator
    }
    
    /// Creates a Signal from the producer, then attaches the given observer to
    /// the Signal as an observer.
    ///
    /// Returns a Disposable which can be used to interrupt the work associated
    /// with the signal and immediately send an `Interrupted` event.
    
    @discardableResult
    public func start() {
        if !started {
            started = true
            
            let observer = Observer<Value, ErrorType> { event in
                // Pass event downstream
                self.observers.forEach { (observer) in
                    observer.action(event)
                }
                
                // If event is terminating dispose of the handlerDisposable.
                if event.isTerminating {
                    self.handlerDisposable?.dispose()
                }
            }
            
            handlerDisposable = startHandler(observer)
            
            // The cancel disposable should send interrupted and then dispose of the 
            // disposable produced by the startHandler.
            cancelDisposable = ActionDisposable { [weak self] in
                observer.sendInterrupted()
                self?.handlerDisposable?.dispose()
            }
        }
    }
    
    public func stop() {
        cancelDisposable?.dispose()
        started = false
    }
    
    /// Adds an observer to the ColdSignal which observes any future events from the
    /// ColdSignal. If the Signal has already terminated, the observer will immediately
    /// receive an `Interrupted` event.
    ///
    /// Returns a Disposable which can be used to disconnect the observer. Disposing
    /// of the Disposable will have no effect on the Signal itself.
    @discardableResult
    public func add(observer: Observer<Value, ErrorType>) -> Disposable? {
        let token = self.observers.insert(value: observer)
        return ActionDisposable {
            self.observers.removeValueForToken(token: token)
        }
    }
    
}

extension ColdSignal: CustomDebugStringConvertible {
    
    public var debugDescription: String {
        let obs = Array(self.observers.map { String(describing: $0) })
        return "ColdSignal[\(obs.joined(separator: ", "))]"
    }
    
}

public protocol ColdSignalType: SignalType {
    
    /// The exposed raw signal that underlies the ColdSignalType
    var coldSignal: ColdSignal<Value, ErrorType> { get }
    
    /// Invokes the closure provided upon initialization, and passes in a newly
    /// created observer to which events can be sent.
    func start()
    
    /// Stops the ColdSignal by sending an interrupt to all of it's
    /// observers and then invoking the disposable returned by the closure
    /// that was provided upon initialization.
    func stop()
    
}

public extension ColdSignalType {
    
    /// Invokes the closure provided upon initialization, and passes in a newly
    /// created observer to which events can be sent.
    func start() {
        coldSignal.start()
    }
    
    /// Stops the ColdSignal by sending an interrupt to all of it's
    /// observers and then invoking the disposable returned by the closure
    /// that was provided upon initialization.
    func stop() {
        coldSignal.stop()
    }

}

public extension ColdSignalType {
    
    /// Creates a ColdSignal, adds exactly one observer, and then immediately
    /// invokes start on the ColdSignal.
    ///
    /// Returns a Disposable which can be used to dispose of the added observer.
    @discardableResult
    public func start(with observer: Observer<Value, ErrorType>) -> Disposable? {
        let disposable = coldSignal.add(observer: observer)
        self.coldSignal.start()
        return disposable
    }

    /// Creates a ColdSignal, adds exactly one observer, and then immediately
    /// invokes start on the ColdSignal.<commit_msg>Added signal property to ColdSignalType extension instead.<commit_after>//
//  SignalProducer.swift
//  Edge
//
//  Created by <NAME> on 5/29/16.
//
//

import Foundation

public final class ColdSignal<Value, ErrorType: Error>: ColdSignalType, InternalSignalType, SpecialSignalGenerator {
    internal var observers = Bag<Observer<Value, ErrorType>>()
    
    public var coldSignal: ColdSignal {
        return self
    }
    
    internal let startHandler: (Observer<Value, ErrorType>) -> Disposable?
    
    private var cancelDisposable: Disposable?
    
    private var handlerDisposable: Disposable?
    
    private var started = false
    
    /// Initializes a ColdSignal that will invoke the given closure at the
    /// invocation of `start()`.
    ///
    /// The events that the closure puts into the given observer will become
    /// the events sent to this ColdSignal.
    ///
    /// In order to stop or dispose of the signal, invoke `stop()`. Calling this method
    /// will dispose of the disposable returned by the given closure.
    /// 
    /// Invoking `start()` will have no effect until the signal is stopped. After
    /// `stop()` is called this process may be repeated.
    public init(_ generator: @escaping (Observer<Value, ErrorType>) -> Disposable?) {
        self.startHandler = generator
    }
    
    /// Creates a Signal from the producer, then attaches the given observer to
    /// the Signal as an observer.
    ///
    /// Returns a Disposable which can be used to interrupt the work associated
    /// with the signal and immediately send an `Interrupted` event.
    
    @discardableResult
    public func start() {
        if !started {
            started = true
            
            let observer = Observer<Value, ErrorType> { event in
                // Pass event downstream
                self.observers.forEach { (observer) in
                    observer.action(event)
                }
                
                // If event is terminating dispose of the handlerDisposable.
                if event.isTerminating {
                    self.handlerDisposable?.dispose()
                }
            }
            
            handlerDisposable = startHandler(observer)
            
            // The cancel disposable should send interrupted and then dispose of the 
            // disposable produced by the startHandler.
            cancelDisposable = ActionDisposable { [weak self] in
                observer.sendInterrupted()
                self?.handlerDisposable?.dispose()
            }
        }
    }
    
    public func stop() {
        cancelDisposable?.dispose()
        started = false
    }
    
    /// Adds an observer to the ColdSignal which observes any future events from the
    /// ColdSignal. If the Signal has already terminated, the observer will immediately
    /// receive an `Interrupted` event.
    ///
    /// Returns a Disposable which can be used to disconnect the observer. Disposing
    /// of the Disposable will have no effect on the Signal itself.
    @discardableResult
    public func add(observer: Observer<Value, ErrorType>) -> Disposable? {
        let token = self.observers.insert(value: observer)
        return ActionDisposable {
            self.observers.removeValueForToken(token: token)
        }
    }
    
}

extension ColdSignal: CustomDebugStringConvertible {
    
    public var debugDescription: String {
        let obs = Array(self.observers.map { String(describing: $0) })
        return "ColdSignal[\(obs.joined(separator: ", "))]"
    }
    
}

public protocol ColdSignalType: SignalType {
    
    /// The exposed raw signal that underlies the ColdSignalType
    var coldSignal: ColdSignal<Value, ErrorType> { get }
    
    /// Invokes the closure provided upon initialization, and passes in a newly
    /// created observer to which events can be sent.
    func start()
    
    /// Stops the ColdSignal by sending an interrupt to all of it's
    /// observers and then invoking the disposable returned by the closure
    /// that was provided upon initialization.
    func stop()
    
}

public extension ColdSignalType {
    
    public var signal: Signal<Value, ErrorType> {
        return self.identity
    }
    
    /// Invokes the closure provided upon initialization, and passes in a newly
    /// created observer to which events can be sent.
    func start() {
        coldSignal.start()
    }
    
    /// Stops the ColdSignal by sending an interrupt to all of it's
    /// observers and then invoking the disposable returned by the closure
    /// that was provided upon initialization.
    func stop() {
        coldSignal.stop()
    }

}

public extension ColdSignalType {
    
    /// Creates a ColdSignal, adds exactly one observer, and then immediately
    /// invokes start on the ColdSignal.
    ///
    /// Returns a Disposable which can be used to dispose of the added observer.
    @discardableResult
    public func start(with observer: Observer<Value, ErrorType>) -> Disposable? {
        let disposable = coldSignal.add(observer: observer)
        self.coldSignal.start()
        return disposable
    }

    /// Creates a ColdSignal, adds exactly one observer, and then immediately
    /// invokes start on the ColdSignal.
{'fraction_non_alphanumeric': 0.08037667649576714, 'fraction_numerical': 0.0011414439265671073, 'mean_word_length': 2.138507462686567, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 33, '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': '1039182', 'n_tokens_mistral': 2700, 'n_tokens_neox': 2541, 'n_words': 1009}