Skip to content

Instantly share code, notes, and snippets.

@Upstarts
Last active February 21, 2023 23:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Upstarts/cb5c0e59383148c97d9b2370d8d9e438 to your computer and use it in GitHub Desktop.
Save Upstarts/cb5c0e59383148c97d9b2370d8d9e438 to your computer and use it in GitHub Desktop.
//
// Rx+Input.swift
//
import RxSwift
import RxRelay
///
struct Input {
@propertyWrapper
class Stream<Value, RxPropertyType: ObservableConvertibleType> where Value == RxPropertyType.Element {
///
let rx: RxPropertyType
fileprivate let input: AnyRxInput<Value>
/**
*/
init(value: Value,
_ rxPropertyType: RxPropertyType.Type) where RxPropertyType: RxBehaviorPropertyInitializable & RxRelayPropertyAcceptable {
let rxProperty = rxPropertyType.init(value: value)
rx = rxProperty
input = .init(rxProperty)
}
/**
*/
init(_ rxPropertyType: RxPropertyType.Type) where RxPropertyType: RxPublishPropertyInitializable & RxRelayPropertyAcceptable, RxPropertyType.Element == Value {
let rxProperty = rxPropertyType.init()
rx = rxProperty
input = .init(rxProperty)
}
/**
*/
init(value: Value,
_ rxPropertyType: RxPropertyType.Type) where RxPropertyType: RxBehaviorPropertyInitializable & ObserverType, RxPropertyType.Element == Value {
let rxProperty = rxPropertyType.init(value: value)
rx = rxProperty
input = .init(rxProperty.asObserver())
}
/**
*/
init(_ rxPropertyType: RxPropertyType.Type) where RxPropertyType: RxPublishPropertyInitializable & ObserverType, RxPropertyType.Element == Value {
let rxProperty = rxPropertyType.init()
rx = rxProperty
input = .init(rxProperty.asObserver())
}
/**
*/
init(replay: RxReplayStrategy) where RxPropertyType == ReplaySubject<Value> {
let replaySubject: ReplaySubject<Value>
if let replayCount = replay.count {
replaySubject = ReplaySubject.create(bufferSize: replayCount)
} else {
replaySubject = ReplaySubject.createUnbounded()
}
rx = replaySubject
input = .init(replaySubject.asObserver())
}
///
var wrappedValue: AnyRxInput<Value> {
input
}
}
}
// MARK: - Relay
extension Input {
///
@propertyWrapper
class Relay<Value, RxPropertyType: ObservableConvertibleType>: Stream<Value, RxPropertyType> where Value == RxPropertyType.Element {
init(value: Value) where RxPropertyType == BehaviorRelay<Value> {
super.init(value: value, BehaviorRelay.self)
}
init() where RxPropertyType == PublishRelay<Value> {
super.init(PublishRelay<Value>.self)
}
///
override var wrappedValue: AnyRxInput<Value> {
input
}
}
}
// MARK: - Subject
extension Input {
///
@propertyWrapper
class Subject<Value, RxPropertyType: ObservableConvertibleType>: Stream<Value, RxPropertyType> where Value == RxPropertyType.Element {
init(value: Value) where RxPropertyType == BehaviorSubject<Value> {
super.init(value: value, BehaviorSubject.self)
}
init() where RxPropertyType == PublishSubject<Value> {
super.init(PublishSubject.self)
}
override init(replay: RxReplayStrategy) where RxPropertyType == ReplaySubject<Value> {
super.init(replay: replay)
}
///
override var wrappedValue: AnyRxInput<Value> {
input
}
}
}
// MARK: - AnyRxInput
///
class AnyRxInput<Value>: ObserverType {
typealias Element = Value
private let acceptValue: (Value) -> Void
private var acceptError: ((Error) -> Void)?
private var complete: (() -> Void)?
/**
*/
init<RxRelayProperty: RxRelayPropertyAcceptable>(_ relay: RxRelayProperty) where RxRelayProperty.Element == Value {
acceptValue = { [weak relay] value in
relay?.accept(value)
}
}
/**
*/
init(_ observer: AnyObserver<Value>) {
acceptValue = { value in
observer.onNext(value)
}
acceptError = { error in
observer.onError(error)
}
complete = {
observer.onCompleted()
}
}
/**
*/
func on(_ event: Event<Element>) {
switch event {
case .next(let element):
acceptValue(element)
case .error(let error):
acceptError?(error)
case .completed:
complete?()
}
}
}
// MARK: - Helper protocols
// MARK: RxRelayPropertyAcceptable
///
protocol RxRelayPropertyAcceptable: AnyObject {
associatedtype Element
func accept(_ event: Element)
}
///
extension BehaviorRelay: RxRelayPropertyAcceptable {}
extension PublishRelay: RxRelayPropertyAcceptable {}
// 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