Created
October 21, 2016 18:54
-
-
Save lorentey/a44b07380bc0a02abad6b6483ee9532f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
protocol Sink { | |
func receive() | |
} | |
protocol Source { | |
associatedtype Value | |
func subscribe(_ sink: Sink) -> Int | |
func unsubscribe(_ token: Int) | |
var valueInTransit: Value { get } | |
} | |
class Signal<Value>: Source { | |
private var _sinks: [Int: Sink] = [:] | |
private var _nextKey = 0 | |
private var _value: Value? = nil | |
func subscribe(_ sink: Sink) -> Int { | |
let key = _nextKey | |
_sinks[key] = sink | |
_nextKey += 1 | |
return key | |
} | |
var valueInTransit: Value { | |
return _value! | |
} | |
func unsubscribe(_ key: Int) { | |
_sinks[key] = nil | |
} | |
func send(_ value: Value) { | |
precondition(_value == nil) | |
_value = value | |
_sinks.forEach { _, sink in sink.receive() } | |
_value = nil | |
} | |
} | |
extension Source { | |
func subscribe(_ sink: @escaping (Value) -> Void) -> Int { | |
return subscribe(ClosureSink(source: self, sink: sink)) | |
} | |
} | |
struct ClosureSink<S: Source>: Sink { | |
let source: S | |
let sink: (S.Value) -> Void | |
func receive() { sink(source.valueInTransit) } | |
} | |
class Foo { | |
func receive(_ value: String, with context: Int) { | |
print("\(value) from Foo with context \(context)") | |
} | |
} | |
struct FooSink<S: Source where S.Value == String>: Sink { | |
let source: S | |
let target: Foo | |
let context: Int | |
func receive() { target.receive(source.valueInTransit, with: context) } | |
} | |
let foo = Foo() | |
let signal = Signal<String>() | |
let k1 = signal.subscribe { print("\($0) from closure observer") } | |
// Note that FooSink fits in 3 words, so Sink's existential probably won't allocate a box for it. | |
let k2 = signal.subscribe(FooSink(source: signal, target: foo, context: 42)) | |
signal.send("Hello") | |
// => Hello from closure observer | |
// => Hello from Foo with context 42 | |
signal.unsubscribe(k1) | |
signal.unsubscribe(k2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment