Last active
July 6, 2018 09:52
-
-
Save lorentey/09eccfaa34fd75a4b2d0ff6230185fa1 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
protocol Sink { | |
associatedtype Value | |
func receive(_ value: Value) | |
} | |
// This assumes Generalized Existentials are a thing | |
// https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials | |
typealias AnySink<Value> = Any<Sink where .Value == Value> | |
protocol Source { | |
associatedtype Value | |
func subscribe(_ sink: Sink) -> Int | |
func unsubscribe(_ token: Int) | |
} | |
class Signal<Value>: Source { | |
private var _sinks: [Int: AnySink<Value>] = [:] | |
private var _nextKey = 0 | |
func subscribe(_ sink: Sink) -> Int { | |
let key = _nextKey | |
_sinks[key] = sink | |
_nextKey += 1 | |
return key | |
} | |
func unsubscribe(_ key: Int) { | |
_sinks[key] = nil | |
} | |
func send(_ value: Value) { | |
_sinks.forEach { _, sink in sink.receive(value) } | |
} | |
} | |
extension Source { | |
func subscribe(_ sink: @escaping (Value) -> Void) -> Int { | |
return subscribe(ClosureSink(source: self, sink: sink)) | |
} | |
} | |
struct ClosureSink<Value>: Sink { | |
let sink: (Value) -> Void | |
func receive(_ value: Value) { | |
sink(value) | |
} | |
} | |
class Foo { | |
func receive(_ value: String, with context: Int) { | |
print("\(value) from Foo with context \(context)") | |
} | |
} | |
struct FooSink: Sink { | |
let target: Foo | |
let context: Int | |
func receive(_ value: String) { target.receive(value, 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 AnySink 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