1 module cmdline.event;
2 
3 import std.stdio;
4 import cmdline.command;
5 
6 alias EventCallback_1 = void delegate();
7 alias EventCallback_2 = void delegate(string val);
8 alias EventCallback_3 = void delegate(bool isErrMode);
9 alias EventCallback_4 = void delegate(string[] vals);
10 
11 struct EventFn {
12     EventCallback_1 _fn1;
13     EventCallback_2 _fn2;
14     EventCallback_3 _fn3;
15     EventCallback_4 _fn4;
16 
17     void opCall() const {
18         _fn1();
19     }
20 
21     void opCall(string val) const {
22         _fn2(val);
23     }
24 
25     void opCall(bool isErrMode) const {
26         _fn3(isErrMode);
27     }
28 
29     void opCall(string[] vals) const {
30         _fn4(vals);
31     }
32 
33     auto opAssign(EventCallback_1 value) {
34         this._fn1 = value;
35         return this;
36     }
37 
38     auto opAssign(EventCallback_2 value) {
39         this._fn2 = value;
40         return this;
41     }
42 
43     auto opAssign(EventCallback_3 value) {
44         this._fn3 = value;
45         return this;
46     }
47 
48     auto opAssign(EventCallback_4 value) {
49         this._fn4 = value;
50         return this;
51     }
52 }
53 
54 class EventManager {
55 private:
56     EventFn[string] eventMap;
57 
58 public:
59     alias Self = typeof(this);
60 
61     Self on(string eventName, EventCallback_1 callback) {
62         auto ptr = eventName in eventMap;
63         assert(!ptr || (*ptr)._fn1 is null);
64         if (ptr) {
65             eventMap[eventName] = callback;
66             return this;
67         }
68         EventFn fn;
69         eventMap[eventName] = fn = callback;
70         return this;
71     }
72 
73     Self on(string eventName, EventCallback_2 callback) {
74         auto ptr = eventName in eventMap;
75         assert(!ptr || (*ptr)._fn2 is null);
76         if (ptr) {
77             eventMap[eventName] = callback;
78             return this;
79         }
80         EventFn fn;
81         eventMap[eventName] = fn = callback;
82         eventMap[eventName] = callback;
83         return this;
84     }
85 
86     Self on(string eventName, EventCallback_3 callback) {
87         auto ptr = eventName in eventMap;
88         assert(!ptr || (*ptr)._fn3 is null);
89         if (ptr) {
90             eventMap[eventName] = callback;
91             return this;
92         }
93         EventFn fn;
94         eventMap[eventName] = fn = callback;
95         eventMap[eventName] = callback;
96         return this;
97     }
98 
99     Self on(string eventName, EventCallback_4 callback) {
100         auto ptr = eventName in eventMap;
101         assert(!ptr || (*ptr)._fn4 is null);
102         if (ptr) {
103             eventMap[eventName] = callback;
104             return this;
105         }
106         EventFn fn;
107         eventMap[eventName] = fn = callback;
108         eventMap[eventName] = callback;
109         return this;
110     }
111 
112     bool emit(string eventName, string val) const {
113         auto fn_ptr = eventName in eventMap;
114         if (!fn_ptr)
115             return false;
116         auto fn = *fn_ptr;
117         fn(val);
118         return true;
119     }
120 
121     bool emit(string eventName, string[] vals) const {
122         auto fn_ptr = eventName in eventMap;
123         if (!fn_ptr)
124             return false;
125         auto fn = *fn_ptr;
126         fn(vals);
127         return true;
128     }
129 
130     bool emit(string eventName) const {
131         auto fn_ptr = eventName in eventMap;
132         if (!fn_ptr)
133             return false;
134         auto fn = *fn_ptr;
135         fn();
136         return true;
137     }
138 
139     bool emit(string eventName, bool isErrMode) const {
140         auto fn_ptr = eventName in eventMap;
141         if (!fn_ptr)
142             return false;
143         auto fn = *fn_ptr;
144         fn(isErrMode);
145         return true;
146     }
147 
148     bool removeEvent(string eventName) {
149         return this.eventMap.remove(eventName);
150     }
151 }
152 
153 unittest {
154     import std.conv;
155 
156     int count = 0;
157     bool fn1_called, fn2_called;
158 
159     EventManager em = new EventManager;
160 
161     em.on("fn1", () { count += 12; fn1_called = true; });
162     em.on("fn2", () { count -= 12; fn2_called = true; });
163     em.emit("fn1");
164     em.emit("fn2");
165     assert(!count && fn1_called && fn2_called);
166 }