1 module carbon.event; 2 3 import std.algorithm, 4 phobosx.signal, // 5 std.variant; 6 7 version(D_LP64) {} 8 else: 9 10 public import phobosx.signal : RestrictedSignal; 11 12 13 struct FiredContext 14 { 15 Variant sender; 16 string file; 17 size_t line; 18 string funcName; 19 string prettyFuncName; 20 } 21 22 23 struct EventManager(T...) 24 { 25 ref RestrictedSignal!(FiredContext, T) signalImpl() @property { return _signalImpl; } 26 private Signal!(FiredContext, T) _signalImpl; 27 alias signalImpl this; 28 29 void disable() 30 { 31 _disable = true; 32 } 33 34 35 void enable() 36 { 37 _disable = false; 38 } 39 40 41 void emit()(auto ref T args, string file = __FILE__, size_t line = __LINE__, 42 string func = __FUNCTION__, string preFunc = __PRETTY_FUNCTION__) 43 { 44 emit(null, forward!args, file, line, func, preFunc); 45 } 46 47 48 void emit(S)(S sender, auto ref T args, string file = __FILE__, size_t line = __LINE__, 49 string func = __FUNCTION__, string preFunc = __PRETTY_FUNCTION__) 50 { 51 FiredContext ctx; 52 ctx.sender = sender; 53 ctx.file = file; 54 ctx.line = line; 55 ctx.funcName = func; 56 ctx.prettyFuncName = preFunc; 57 58 emit(ctx, forward!args); 59 } 60 61 62 private: 63 void emit()(FiredContext ctx, auto ref T args) 64 { 65 if(!_disable){ 66 _signalImpl.emit(ctx, forward!args); 67 } 68 } 69 70 71 bool _disable; 72 } 73 74 unittest 75 { 76 auto event = EventManager!bool(); 77 78 bool bCalled = false; 79 event.strongConnect(delegate(FiredContext ctx, bool b){ 80 assert(b); 81 assert(ctx.sender == null); 82 bCalled = true; 83 }); 84 85 event.emit(true); 86 assert(bCalled); 87 88 bCalled = false; 89 event.disable(); 90 event.emit(true); 91 assert(!bCalled); 92 } 93 94 95 struct SeqEventManager(size_t N, T...) 96 { 97 ref RestrictedSignal!(FiredContext, T) opIndex(size_t i) 98 in{ 99 assert(i < N); 100 } 101 body{ 102 return _signals[i]; 103 } 104 105 106 void disable() 107 { 108 _disable = true; 109 } 110 111 112 void enable() 113 { 114 _disable = false; 115 } 116 117 118 void emit()(auto ref T args, string file = __FILE__, size_t line = __LINE__, 119 string func = __FUNCTION__, string preFunc = __PRETTY_FUNCTION__) 120 { 121 emit(null, forward!args, file, line, func, preFunc); 122 } 123 124 125 void emit(S)(S sender, auto ref T args, string file = __FILE__, size_t line = __LINE__, 126 string func = __FUNCTION__, string preFunc = __PRETTY_FUNCTION__) 127 { 128 FiredContext ctx; 129 ctx.sender = sender; 130 ctx.file = file; 131 ctx.line = line; 132 ctx.funcName = func; 133 ctx.prettyFuncName = preFunc; 134 135 emit(ctx, forward!args); 136 } 137 138 139 private: 140 void emit()(FiredContext ctx, auto ref T args) 141 { 142 if(!_disable){ 143 foreach(i, ref e; _signals) 144 e.emit(ctx, forward!args); 145 } 146 } 147 148 149 private: 150 Signal!(FiredContext, T)[N] _signals; 151 bool _disable; 152 } 153 154 unittest 155 { 156 SeqEventManager!(3, bool) event; 157 158 size_t cnt; 159 size_t[3] ns; 160 event[0].strongConnect(delegate(FiredContext ctx, bool b){ 161 assert(b); 162 assert(ctx.sender == null); 163 ns[0] = cnt; 164 ++cnt; 165 }); 166 167 event[1].strongConnect(delegate(FiredContext ctx, bool b){ 168 assert(b); 169 assert(ctx.sender == null); 170 ns[1] = cnt; 171 ++cnt; 172 }); 173 174 event[2].strongConnect(delegate(FiredContext ctx, bool b){ 175 assert(b); 176 assert(ctx.sender == null); 177 ns[2] = cnt; 178 ++cnt; 179 }); 180 181 event.emit(true); 182 assert(cnt == 3); 183 assert(ns[] == [0, 1, 2]); 184 }