<commit_before>//
//  SharedSequence.swift
//  RxCocoa
//
//  Created by <NAME> on 8/27/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

#if !RX_NO_MODULE
    import RxSwift
#endif

/**
    Trait that represents observable sequence that shares computation resources with following properties:

    - it never fails
    - it delivers events on `SharingStrategy.scheduler`
    - sharing strategy is customizable using `SharingStrategy.share` behavior

    `SharedSequence<Element>` can be considered a builder pattern for observable sequences that share computation resources.

    To find out more about units and how to use them, please visit `Documentation/Traits.md`.
*/
public struct SharedSequence<S: SharingStrategyProtocol, Element> : SharedSequenceConvertibleType {
    public typealias E = Element
    public typealias SharingStrategy = S

    let _source: Observable<E>

    init(_ source: Observable<E>) {
        self._source = S.share(source)
    }

    init(raw: Observable<E>) {
        self._source = raw
    }

    #if EXPANDABLE_SHARED_SEQUENCE
    /**
     This method is extension hook in case this unit needs to extended from outside the library.
     
     By defining `EXPANDABLE_SHARED_SEQUENCE` one agrees that it's up to him to ensure shared sequence
     properties are preserved after extension.
    */
    public static func createUnsafe<O: ObservableType>(source: O) -> SharedSequence<S, O.E> {
        return SharedSequence<S, O.E>(raw: source.asObservable())
    }
    #endif

    /**
    - returns: Built observable sequence.
    */
    public func asObservable() -> Observable<E> {
        return _source
    }

    /**
    - returns: `self`
    */
    public func asSharedSequence() -> SharedSequence<SharingStrategy, E> {
        return self
    }
}

/**
 Different `SharedSequence` sharing strategies must conform to this protocol.
 */
public protocol SharingStrategyProtocol {
    /**
     Scheduled on which all sequence events will be delivered.
    */
    static var scheduler: SchedulerType { get }

    /**
     Computation resources sharing strategy for multiple sequence observers.
     
     E.g. One can choose `shareReplayWhenConnected`, `shareReplay` or `share`
     as sequence event sharing strategies, but also do something more exotic, like
     implementing promises or lazy loading chains.
    */
    static func share<E>(_ source: Observable<E>) -> Observable<E>
}

/**
A type that can be converted to `SharedSequence`.
*/
public protocol SharedSequenceConvertibleType : ObservableConvertibleType {
    associatedtype SharingStrategy: SharingStrategyProtocol

    /**
    Converts self to `SharedSequence`.
    */
    func asSharedSequence() -> SharedSequence<SharingStrategy, E>
}

extension SharedSequenceConvertibleType {
    public func asObservable() -> Observable<E> {
        return asSharedSequence().asObservable()
    }
}


extension SharedSequence {

    /**
    Returns an empty observable sequence, using the specified scheduler to send out the single `Completed` message.

    - returns: An observable sequence with no elements.
    */
    public static func empty() -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.empty().subscribeOn(S.scheduler))
    }

    /**
    Returns a non-terminating observable sequence, which can be used to denote an infinite duration.

    - returns: An observable sequence whose observers will never get called.
    */
    public static func never() -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.never())
    }

    /**
    Returns an observable sequence that contains a single element.

    - parameter element: Single element in the resulting observable sequence.
    - returns: An observable sequence containing the single specified element.
    */
    public static func just(_ element: E) -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.just(element).subscribeOn(S.scheduler))
    }

    /**
     Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes.

     - parameter observableFactory: Observable factory function to invoke for each observer that subscribes to the resulting sequence.
     - returns: An observable sequence whose observers trigger an invocation of the given observable factory function.
     */
    public static func deferred(_ observableFactory: @escaping () -> SharedSequence<S, E>)
        -> SharedSequence<S, E> {
        return SharedSequence(Observable.deferred { observableFactory().asObservable() })
    }

    /**
    This method creates a new Observable instance with a variable number of elements.

    - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)

    - parameter elements: Elements to generate.
    - returns: The observable sequence whose elements are pulled from the given arguments.
    */
    public static func of(_ elements: E ...) -> SharedSequence<S, E> {
        let source = Observable.from(elements, scheduler: S.scheduler)
        return SharedSequence(raw: source)
    }
}

extension SharedSequence {
    
    /**
    This method converts an array to an observable sequence.
     
    - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)
     
    - returns: The observable sequence whose elements are pulled from the given enumerable sequence.
     */
    public static func from(_ array: [E]) -> SharedSequence<S, E> {
        let source = Observable.from(array, scheduler: S.scheduler)
        return SharedSequence(raw: source)
    }
    
    /**
     This method converts a sequence to an observable sequence.
     
     - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)
     
     - returns: The observable sequence whose elements are pulled from the given enumerable sequence.
    */
    public static func from<S: Sequence>(_ sequence: S) -> SharedSequence<S, E> where S.Iterator.Element == E {
        let source = Observable.from(sequence, scheduler: S.scheduler)
        return SharedSequence(raw: sequence)
    }
    
    /**
     This method converts a optional to an observable sequence.<commit_msg>use source intead of sequence<commit_after>//
//  SharedSequence.swift
//  RxCocoa
//
//  Created by <NAME> on 8/27/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

#if !RX_NO_MODULE
    import RxSwift
#endif

/**
    Trait that represents observable sequence that shares computation resources with following properties:

    - it never fails
    - it delivers events on `SharingStrategy.scheduler`
    - sharing strategy is customizable using `SharingStrategy.share` behavior

    `SharedSequence<Element>` can be considered a builder pattern for observable sequences that share computation resources.

    To find out more about units and how to use them, please visit `Documentation/Traits.md`.
*/
public struct SharedSequence<S: SharingStrategyProtocol, Element> : SharedSequenceConvertibleType {
    public typealias E = Element
    public typealias SharingStrategy = S

    let _source: Observable<E>

    init(_ source: Observable<E>) {
        self._source = S.share(source)
    }

    init(raw: Observable<E>) {
        self._source = raw
    }

    #if EXPANDABLE_SHARED_SEQUENCE
    /**
     This method is extension hook in case this unit needs to extended from outside the library.
     
     By defining `EXPANDABLE_SHARED_SEQUENCE` one agrees that it's up to him to ensure shared sequence
     properties are preserved after extension.
    */
    public static func createUnsafe<O: ObservableType>(source: O) -> SharedSequence<S, O.E> {
        return SharedSequence<S, O.E>(raw: source.asObservable())
    }
    #endif

    /**
    - returns: Built observable sequence.
    */
    public func asObservable() -> Observable<E> {
        return _source
    }

    /**
    - returns: `self`
    */
    public func asSharedSequence() -> SharedSequence<SharingStrategy, E> {
        return self
    }
}

/**
 Different `SharedSequence` sharing strategies must conform to this protocol.
 */
public protocol SharingStrategyProtocol {
    /**
     Scheduled on which all sequence events will be delivered.
    */
    static var scheduler: SchedulerType { get }

    /**
     Computation resources sharing strategy for multiple sequence observers.
     
     E.g. One can choose `shareReplayWhenConnected`, `shareReplay` or `share`
     as sequence event sharing strategies, but also do something more exotic, like
     implementing promises or lazy loading chains.
    */
    static func share<E>(_ source: Observable<E>) -> Observable<E>
}

/**
A type that can be converted to `SharedSequence`.
*/
public protocol SharedSequenceConvertibleType : ObservableConvertibleType {
    associatedtype SharingStrategy: SharingStrategyProtocol

    /**
    Converts self to `SharedSequence`.
    */
    func asSharedSequence() -> SharedSequence<SharingStrategy, E>
}

extension SharedSequenceConvertibleType {
    public func asObservable() -> Observable<E> {
        return asSharedSequence().asObservable()
    }
}


extension SharedSequence {

    /**
    Returns an empty observable sequence, using the specified scheduler to send out the single `Completed` message.

    - returns: An observable sequence with no elements.
    */
    public static func empty() -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.empty().subscribeOn(S.scheduler))
    }

    /**
    Returns a non-terminating observable sequence, which can be used to denote an infinite duration.

    - returns: An observable sequence whose observers will never get called.
    */
    public static func never() -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.never())
    }

    /**
    Returns an observable sequence that contains a single element.

    - parameter element: Single element in the resulting observable sequence.
    - returns: An observable sequence containing the single specified element.
    */
    public static func just(_ element: E) -> SharedSequence<S, E> {
        return SharedSequence(raw: Observable.just(element).subscribeOn(S.scheduler))
    }

    /**
     Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes.

     - parameter observableFactory: Observable factory function to invoke for each observer that subscribes to the resulting sequence.
     - returns: An observable sequence whose observers trigger an invocation of the given observable factory function.
     */
    public static func deferred(_ observableFactory: @escaping () -> SharedSequence<S, E>)
        -> SharedSequence<S, E> {
        return SharedSequence(Observable.deferred { observableFactory().asObservable() })
    }

    /**
    This method creates a new Observable instance with a variable number of elements.

    - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)

    - parameter elements: Elements to generate.
    - returns: The observable sequence whose elements are pulled from the given arguments.
    */
    public static func of(_ elements: E ...) -> SharedSequence<S, E> {
        let source = Observable.from(elements, scheduler: S.scheduler)
        return SharedSequence(raw: source)
    }
}

extension SharedSequence {
    
    /**
    This method converts an array to an observable sequence.
     
    - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)
     
    - returns: The observable sequence whose elements are pulled from the given enumerable sequence.
     */
    public static func from(_ array: [E]) -> SharedSequence<S, E> {
        let source = Observable.from(array, scheduler: S.scheduler)
        return SharedSequence(raw: source)
    }
    
    /**
     This method converts a sequence to an observable sequence.
     
     - seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)
     
     - returns: The observable sequence whose elements are pulled from the given enumerable sequence.
    */
    public static func from<S: Sequence>(_ sequence: S) -> SharedSequence<S, E> where S.Iterator.Element == E {
        let source = Observable.from(sequence, scheduler: S.scheduler)
        return SharedSequence(raw: source)
    }
    
    /**
     This method converts a optional to an observable sequence.
{'fraction_non_alphanumeric': 0.0851709811441355, 'fraction_numerical': 0.0014381591562799617, 'mean_word_length': 3.1052804198097737, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 83, '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': '3515021', 'n_tokens_mistral': 3331, 'n_tokens_neox': 3120, 'n_words': 1169}