Skip to content

Instantly share code, notes, and snippets.

@Upstarts
Last active February 21, 2023 23:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Upstarts/58fa8dd70fe688e74722df5d377f0504 to your computer and use it in GitHub Desktop.
Save Upstarts/58fa8dd70fe688e74722df5d377f0504 to your computer and use it in GitHub Desktop.
//
// 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