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 }