1 module dscord.util.emitter;
2 
3 import vibe.core.concurrency,
4        vibe.core.core;
5 
6 import std.stdio,
7        std.algorithm,
8        std.array,
9        std.variant,
10        std.datetime,
11        core.time;
12 
13 import dscord.util.errors;
14 
15 class EmitterStop : Exception { mixin ExceptionMixin; }
16 
17 interface BoundEmitter {
18   void call(string, Variant);
19 }
20 
21 class BaseEventListener : BoundEmitter {
22   string     name;
23   Emitter    e;
24 
25   void unbind() {
26     this.e.listeners[this.name] = this.e.listeners[this.name].filter!(
27       (li) => li != this).array;
28   }
29 
30   void call(string name, Variant arg) {
31 
32   }
33 }
34 
35 class EventListener : BaseEventListener {
36   void delegate(Variant arg)  func;
37 
38   this(Emitter e, string name, void delegate(Variant) f) {
39     this.e = e;
40     this.name = name;
41     this.func = f;
42   }
43 
44   override void call(string name, Variant arg) {
45     this.func(arg);
46   }
47 }
48 
49 class AllEventListener : BaseEventListener {
50   void delegate(string, Variant)  func;
51 
52   this(Emitter e, void delegate(string, Variant) f) {
53     this.e = e;
54     this.func = f;
55   }
56 
57   override void call(string name, Variant arg) {
58     this.func(name, arg);
59   }
60 }
61 
62 class Emitter {
63   BoundEmitter[][string]  listeners;
64 
65   EventListener on(string event, void delegate() f) {
66     auto li = new EventListener(this, event, (arg) {
67       try { f(); } catch (EmitterStop) { return; }
68     });
69 
70     this.listeners[event] ~= li;
71     return li;
72   }
73 
74   EventListener listen(T)(void delegate(T) f) {
75     auto li = new EventListener(this, T.stringof, (arg) {
76       try { f(arg.get!T); } catch (EmitterStop) { return; }
77     });
78 
79     this.listeners[T.stringof] ~= li;
80     return li;
81   }
82 
83   EventListener listenRaw(string event, void delegate(Variant) f) {
84     auto li = new EventListener(this, event, f);
85     this.listeners[event] ~= li;
86     return li;
87   }
88 
89   AllEventListener listenAll(void delegate(string, Variant) f) {
90     auto li = new AllEventListener(this, f);
91     this.listeners[""] ~= li;
92     return li;
93   }
94 
95   void emit(T)(T obj) {
96     this.emitByName!T(T.stringof, obj, false);
97     this.emitByName!T(T.stringof, obj, true);
98   }
99 
100   void emitByName(T)(string name, T obj, bool all) {
101     if (!((all ? "" : name) in this.listeners)) {
102       return;
103     }
104 
105     auto v = Variant(obj);
106 
107     foreach (func; this.listeners[all ? "" : name]) {
108       runTask(&func.call, name, v);
109     }
110   }
111 }