Last active
February 21, 2023 23:01
-
-
Save Upstarts/58fa8dd70fe688e74722df5d377f0504 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Rx+Output.swift | |
// | |
import RxSwift | |
import RxRelay | |
/// | |
struct Output { | |
@propertyWrapper | |
class Stream<InputValue, | |
OutputValue, | |
RxPropertyType: ObservableConvertibleType, | |
OutputSequence: ObservableConvertibleType> where RxPropertyType.Element == InputValue, OutputSequence.Element == OutputValue { | |
let rx: RxPropertyType | |
let sequence: OutputSequence | |
// MARK: - Init with `RxBehaviorPropertyInitializable` | |
init( | |
value: InputValue, | |
_ rxPropertyType: RxPropertyType.Type, | |
mutator: ((RxPropertyType) -> OutputSequence)? = nil) where RxPropertyType: RxBehaviorPropertyInitializable, OutputSequence == Observable<RxPropertyType.Element> { | |
let rxProperty = rxPropertyType.init(value: value) | |
rx = rxProperty | |
sequence = mutator?(rxProperty) ?? rxProperty.asObservable() | |
} | |
init(value: InputValue, | |
_ rxPropertyType: RxPropertyType.Type, | |
mutator: ((RxPropertyType) -> OutputSequence)) where RxPropertyType: RxBehaviorPropertyInitializable { | |
let rxProperty = rxPropertyType.init(value: value) | |
rx = rxProperty | |
sequence = mutator(rxProperty) | |
} | |
// MARK: - Init with `RxPublishPropertyInitializable` | |
init(_ rxPropertyType: RxPropertyType.Type, | |
mutator: ((RxPropertyType) -> OutputSequence)? = nil) where RxPropertyType: RxPublishPropertyInitializable, OutputSequence == Observable<RxPropertyType.Element> { | |
let rxProperty = rxPropertyType.init() | |
rx = rxProperty | |
sequence = mutator?(rxProperty) ?? rxProperty.asObservable() | |
} | |
init(_ rxPropertyType: RxPropertyType.Type, | |
mutator: ((RxPropertyType) -> OutputSequence)) where RxPropertyType: RxPublishPropertyInitializable { | |
let rxProperty = rxPropertyType.init() | |
rx = rxProperty | |
sequence = mutator(rxProperty) | |
} | |
// MARK: - Init with `ReplaySubject` | |
/** | |
`InputValue == OutputValue` | |
*/ | |
init(replay: RxReplayStrategy, | |
mutator: ((RxPropertyType) -> OutputSequence)? = nil) where RxPropertyType == ReplaySubject<OutputValue>, OutputSequence == Observable<RxPropertyType.Element> { | |
let replaySubject: ReplaySubject<RxPropertyType.Element>! | |
switch replay { | |
case .once: | |
replaySubject = ReplaySubject.create(bufferSize: 1) | |
case .none: | |
replaySubject = ReplaySubject.create(bufferSize: 0) | |
case .custom(let bufferSize): | |
replaySubject = ReplaySubject.create(bufferSize: bufferSize) | |
case .all: | |
replaySubject = ReplaySubject.createUnbounded() | |
} | |
rx = replaySubject | |
sequence = mutator?(replaySubject) ?? replaySubject.asObservable() | |
} | |
/** | |
Mandatory `mutator` | |
`InputValue != OutputValue` | |
*/ | |
init(replay: RxReplayStrategy, | |
mutator: ((RxPropertyType) -> OutputSequence)) where RxPropertyType == ReplaySubject<InputValue> { | |
var replaySubject: ReplaySubject<InputValue> | |
switch replay { | |
case .once: | |
replaySubject = ReplaySubject.create(bufferSize: 1) | |
case .none: | |
replaySubject = ReplaySubject.create(bufferSize: 0) | |
case .custom(let bufferSize): | |
replaySubject = ReplaySubject.create(bufferSize: bufferSize) | |
case .all: | |
replaySubject = ReplaySubject.createUnbounded() | |
} | |
rx = replaySubject | |
sequence = mutator(replaySubject) | |
} | |
/// | |
var wrappedValue: OutputSequence { | |
sequence | |
} | |
} | |
} | |
// MARK: - Relay | |
extension Output { | |
/// | |
@propertyWrapper | |
class Relay<InputValue, | |
OutputValue, | |
RxPropertyType: ObservableConvertibleType, | |
OutputSequence: ObservableConvertibleType>: Stream<InputValue, OutputValue, RxPropertyType, OutputSequence> where RxPropertyType.Element == InputValue, OutputSequence.Element == OutputValue { | |
init(value: InputValue) where RxPropertyType == BehaviorRelay<InputValue>, OutputSequence == Observable<RxPropertyType.Element> { | |
super.init(value: value, BehaviorRelay.self) | |
} | |
init(value: InputValue, mutator: (RxPropertyType) -> OutputSequence) where RxPropertyType == BehaviorRelay<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(value: value, BehaviorRelay.self, mutator: mutator) | |
} | |
init() where RxPropertyType == PublishRelay<InputValue>, OutputSequence == Observable<RxPropertyType.Element> { | |
super.init(PublishRelay.self) | |
} | |
init(mutator: (RxPropertyType) -> OutputSequence) where RxPropertyType == PublishRelay<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(PublishRelay.self, mutator: mutator) | |
} | |
/// | |
override var wrappedValue: OutputSequence { | |
sequence | |
} | |
} | |
} | |
// MARK: - Subject | |
extension Output { | |
/// | |
@propertyWrapper | |
class Subject<InputValue, | |
OutputValue, | |
RxPropertyType: ObservableConvertibleType, | |
OutputSequence: ObservableConvertibleType>: Stream<InputValue, OutputValue, RxPropertyType, OutputSequence> where RxPropertyType.Element == InputValue, OutputSequence.Element == OutputValue { | |
init(value: InputValue) where RxPropertyType == BehaviorSubject<InputValue>, OutputSequence == Observable<RxPropertyType.Element> { | |
super.init(value: value, BehaviorSubject.self) | |
} | |
init(value: InputValue, mutator: (RxPropertyType) -> OutputSequence) where RxPropertyType == BehaviorSubject<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(value: value, BehaviorSubject.self, mutator: mutator) | |
} | |
init() where RxPropertyType == PublishSubject<InputValue>, OutputSequence == Observable<RxPropertyType.Element> { | |
super.init(PublishSubject.self) | |
} | |
init(mutator: (RxPropertyType) -> OutputSequence) where RxPropertyType == PublishSubject<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(PublishSubject.self, mutator: mutator) | |
} | |
init(replay: RxReplayStrategy) where InputValue == OutputValue, RxPropertyType == ReplaySubject<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(replay: replay) | |
} | |
init(replay: RxReplayStrategy, mutator: (RxPropertyType) -> OutputSequence) where RxPropertyType == ReplaySubject<InputValue>, OutputSequence == Observable<OutputValue> { | |
super.init(replay: replay, mutator: mutator) | |
} | |
override var wrappedValue: OutputSequence { | |
sequence | |
} | |
} | |
} | |
// MARK: - Single | |
extension Output { | |
/// | |
@propertyWrapper | |
class Single<InputValue, | |
OutputValue, | |
RxPropertyType: ObservableConvertibleType>: Stream<InputValue, OutputValue, RxPropertyType, RxSwift.Single<OutputValue>> where RxPropertyType.Element == InputValue { | |
init() where InputValue == OutputValue, RxPropertyType == PublishSubject<InputValue> { | |
super.init(PublishSubject.self, mutator: { $0.asSingle() }) | |
} | |
init(map transform: @escaping (InputValue) -> OutputValue) where RxPropertyType == PublishSubject<InputValue> { | |
super.init(PublishSubject.self, mutator: { $0.map(transform).asSingle() }) | |
} | |
override var wrappedValue: RxSwift.Single<OutputValue> { | |
sequence | |
} | |
func succeed(_ value: InputValue) { | |
guard let observer = rx as? AnyObserver<InputValue> else { return } | |
observer.onNext(value) | |
observer.onCompleted() | |
} | |
} | |
} | |
// MARK: - Completable | |
extension Output { | |
@propertyWrapper | |
class Completable: Stream<Never, Never, PublishSubject<Never>, RxSwift.Completable> { | |
init() { | |
super.init(PublishSubject.self, mutator: { $0.asCompletable() }) | |
} | |
override var wrappedValue: RxSwift.Completable { | |
sequence | |
} | |
func complete<Element>() -> AnyObserver<Element> { | |
AnyObserver { [weak rx] observer in | |
rx?.onCompleted() | |
} | |
} | |
} | |
} | |
// MARK: - Helper protocols | |
// MARK: RxPublishPropertyInitializable | |
/// | |
protocol RxPublishPropertyInitializable: ObservableType { | |
init() | |
} | |
/// | |
extension PublishSubject: RxPublishPropertyInitializable {} | |
extension PublishRelay: RxPublishPropertyInitializable {} | |
// MARK: RxBehaviorPropertyInitializable | |
/// | |
protocol RxBehaviorPropertyInitializable: ObservableType { | |
init(value: Element) | |
} | |
/// | |
extension BehaviorSubject: RxBehaviorPropertyInitializable {} | |
extension BehaviorRelay: RxBehaviorPropertyInitializable {} | |
// MARK: - Syntax sugar | |
// MARK: RxReplayStrategy | |
/// | |
enum RxReplayStrategy { | |
case once, all, custom(Int), none | |
var count: Int? { | |
switch self { | |
case .none: return 0 | |
case .once: return 1 | |
case .custom(let bufferSize): return bufferSize | |
default: return nil | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment