1 module vsignal.sink; 2 3 import vsignal.signal; 4 import vsignal.slot : Slot, slot_connect = connect; 5 6 // https://issues.dlang.org/show_bug.cgi?id=5710 7 /** 8 Connect a listener to a Signal. 9 10 A payload can be passed if the function to call is a data member function of the 11 same or if the function accepts as its first parameter a reference to its type. 12 13 Params: 14 pred = the listener to connect. 15 sink = the Sink that holds the signal. 16 instance = the payload to store. 17 18 Returns: A Connection of the listener. 19 */ 20 Connection connect(alias pred, F)(auto ref Sink!F sink) 21 { 22 sink.disconnect!pred; 23 24 import core.lifetime : move; 25 26 with (sink) 27 { 28 Slot!F call; 29 call.slot_connect!pred; 30 signal.calls ~= call.move(); 31 32 Slot!(void delegate(void* signal) @safe pure nothrow) conn; 33 conn.slot_connect!(release!(pred, F))(); 34 35 return Connection(conn.move(), signal); 36 } 37 } 38 39 /// 40 Connection connect(alias pred, T, F)(auto ref Sink!F sink, ref T instance) 41 { 42 sink.disconnect!pred(instance); 43 44 import core.lifetime : move; 45 46 with (sink) 47 { 48 Slot!F call; 49 call.slot_connect!pred(instance); 50 signal.calls ~= call.move(); 51 52 Slot!(void delegate(void* signal) @safe pure nothrow) conn; 53 conn.slot_connect!(release!(pred, T, F))(instance); 54 55 return Connection(conn.move(), signal); 56 } 57 } 58 59 // https://issues.dlang.org/show_bug.cgi?id=5710 60 /++ 61 Disconnects a listener from a Signal. The order is not preserved after the 62 removal. 63 64 Examples: 65 --- 66 void method() {} 67 struct Foo { void method() {} } 68 Foo foo; 69 70 /* ... */ 71 72 // lets assume a signal exists with listeners 73 sink.disconnect!(Foo.method)(foo); // disconnects Foo.method with payload foo 74 sink.disconnect!method; // disconnects method 75 sink.disconnect(foo); // disconnects all listeners with payload foo 76 sink.disconnect(); // disconnects all listeners 77 --- 78 79 Params: 80 pred = the listener to disconnect. 81 sink = the Sink that holds the signal. 82 instance = the payload that composes the listener. 83 +/ 84 void disconnect(alias pred, F)(auto ref Sink!F sink) 85 { 86 import std.algorithm.mutation : remove, SwapStrategy; 87 import std.algorithm.searching : countUntil; 88 89 Slot!F call; 90 call.slot_connect!pred; 91 92 with (sink) 93 { 94 const index = signal.calls.countUntil(call); 95 96 if (index > -1) 97 signal.calls = signal.calls.remove!(SwapStrategy.unstable)(index); 98 } 99 } 100 101 /// 102 void disconnect(alias pred, T, F)(auto ref Sink!F sink, ref T instance) 103 { 104 import std.algorithm.mutation : remove, SwapStrategy; 105 import std.algorithm.searching : countUntil; 106 107 Slot!F call; 108 call.slot_connect!pred(instance); 109 110 with (sink) 111 { 112 const index = signal.calls.countUntil(call); 113 114 if (index > -1) 115 signal.calls = signal.calls.remove!(SwapStrategy.unstable)(index); 116 } 117 } 118 119 /// 120 void disconnect(T, F)(auto ref Sink!F sink, ref T instance) 121 { 122 import std.algorithm.mutation : remove, SwapStrategy; 123 124 with (sink) 125 { 126 signal.calls = signal.calls.remove!(call => call.payload is &instance , SwapStrategy.unstable); 127 } 128 } 129 130 /// 131 void disconnect(F)(auto ref Sink!F sink) 132 { 133 sinksignal.calls = []; 134 } 135 136 // https://issues.dlang.org/show_bug.cgi?id=5710 137 /** 138 Used as a bridge between Sink and Connection to correctly disconnect a listener 139 from a signal. 140 141 Params: 142 pred = the listener to disconnect, 143 signal = the signal that contains the listener. 144 instance = the payload that is attached to the listener. 145 */ 146 private void release(alias pred, F)(void* signal) 147 { 148 Sink!F(() @trusted { return cast(Signal!F*) signal; } ()).disconnect!pred(); 149 } 150 151 /// 152 private void release(alias pred, T, F)(ref T instance, void* signal) 153 { 154 Sink!F(() @trusted { return cast(Signal!F*) signal; } ()).disconnect!pred(instance); 155 } 156 157 struct Sink(F) 158 { 159 this(scope Signal!F* sig) 160 { 161 signal = sig; 162 } 163 164 size_t length() const @property 165 { 166 return signal.length; 167 } 168 169 bool empty() const @property 170 { 171 return signal.empty; 172 } 173 174 private: 175 Signal!F* signal; 176 } 177 178 struct Connection 179 { 180 bool opCast(T : bool)() const 181 { 182 return disconnect; 183 } 184 185 void release()() 186 { 187 if (disconnect) 188 { 189 disconnect(signal); 190 disconnect.reset(); 191 } 192 } 193 194 private: 195 Slot!(void delegate(void*) @safe pure nothrow) disconnect; 196 void* signal; 197 }