1 module observable; 2 3 import mutex : DummyMutex; 4 5 private struct Observer(T) { 6 void delegate(ref const(T)) @safe onMsg; 7 void delegate() @safe onClose; 8 } 9 10 struct Observable(T, Mutex = DummyMutex) { 11 import std.traits : isImplicitlyConvertible; 12 Observer!(T)[void*] observer; 13 Mutex mutex; 14 alias Type = T; 15 16 T value; 17 18 ~this() @safe { 19 import std.stdio; 20 foreach(ref it; this.observer) { 21 if(it.onClose) { 22 it.onClose(); 23 } 24 } 25 } 26 27 T opCast(T)() { 28 return this.value; 29 } 30 31 typeof(this) opAssign(T newValue) { 32 this.value = newValue; 33 return this; 34 } 35 36 @property size_t length() const @safe pure nothrow @nogc { 37 return this.observer.length; 38 } 39 40 void subscribe(void delegate(ref const(T)) @safe onMsg) @safe pure { 41 this.subscribe(onMsg, null); 42 } 43 44 void subscribe(void delegate(ref const(T)) @safe onMsg, 45 void delegate() @safe onClose) @safe pure 46 { 47 Observer!T ob; 48 ob.onMsg = onMsg; 49 ob.onClose = onClose; 50 51 void* fptr = () @trusted { return cast(void*)(onMsg.funcptr); }(); 52 assert(fptr); 53 this.observer[fptr] = ob; 54 } 55 56 void unSubscribe(void delegate(ref const(T)) @safe onMsg) @safe pure { 57 void* fptr = () @trusted { return cast(void*)(onMsg.funcptr); }(); 58 assert(fptr); 59 60 if(fptr in this.observer) { 61 this.observer.remove(fptr); 62 } 63 } 64 65 void push(S)(auto ref const(S) value) @safe 66 if(isImplicitlyConvertible!(S,T)) 67 { 68 this.value = value; 69 this.publish(); 70 } 71 72 void publish() @safe { 73 foreach(ref it; this.observer) { 74 it.onMsg(this.value); 75 } 76 } 77 } 78 79 unittest { 80 int globalInt = 0; 81 82 void fun(ref const(int) f) @safe { 83 globalInt = f; 84 } 85 86 Observable!int intOb; 87 assert(intOb.length == 0); 88 intOb.subscribe(&fun); 89 assert(intOb.length == 1); 90 intOb.push(10); 91 assert(globalInt == 10); 92 intOb.push(globalInt); 93 assert(globalInt == 10); 94 intOb.unSubscribe(&fun); 95 assert(intOb.length == 0); 96 } 97 98 unittest { 99 import std.conv : to; 100 bool b; 101 102 void fun(ref const(int) f) @safe { 103 int a = 10; 104 } 105 106 void fun1(ref const(int) f) @safe { 107 int c = 10; 108 } 109 110 void fun2() @safe { 111 b = true; 112 } 113 114 { 115 Observable!int ob; 116 ob.subscribe(&fun, &fun2); 117 ob.subscribe(&fun1); 118 assert(ob.length == 2, to!string(ob.length)); 119 ob.push(10); 120 } 121 122 assert(b); 123 } 124 125 unittest { 126 struct Foo { 127 int a; 128 int b; 129 } 130 131 void fun(ref const(Foo) f) @safe { 132 assert(f.b == 10); 133 } 134 135 Observable!(Foo) ob; 136 ob.subscribe(&fun); 137 ob.push(Foo(9,10)); 138 }