Last active
July 6, 2018 09:52
Revisions
-
lorentey revised this gist
Oct 21, 2016 . 1 changed file with 3 additions and 5 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -40,9 +40,8 @@ extension Source { } } struct ClosureSink<Value>: Sink { let sink: (Value) -> Void func receive(_ value: Value) { sink(value) @@ -55,8 +54,7 @@ class Foo { } } struct FooSink: Sink { let target: Foo let context: Int func receive(_ value: String) { target.receive(value, with: context) } -
lorentey created this gist
Oct 21, 2016 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,79 @@ 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<S: Source>: Sink { let source: S let sink: (S.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<S: Source where S.Value == String>: Sink { let source: S 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)