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