1 /**
2   Utilties for handling/listening to events through the dcord bot interface.
3 */
4 
5 module dcord.bot.listener;
6 
7 import std.variant,
8        std..string,
9        std.array;
10 
11 import dcord.types,
12        dcord.gateway,
13        dcord.util.emitter;
14 
15 /**
16   UDA that can be used on a Plugin, informing it that the function will handle
17   all events of type T.
18 
19   Params:
20     T = Event type to listen for
21 */
22 ListenerDef!T Listener(T, EmitterOrder order = EmitterOrder.UNSPECIFIED)() { // stfu
23   return ListenerDef!(T)(T.stringof, order, (event, func) {
24     func(event.get!(T));
25   });
26 }
27 
28 /**
29   Utility struct returned by the UDA.
30 */
31 struct ListenerDef(T) {
32   string clsName;
33   EmitterOrder order;
34   void delegate(Variant, void delegate(T)) func;
35 }
36 
37 /**
38   A ListenerObject represents the configuration/state for a single listener.
39 */
40 class ListenerObject {
41   /** The class name of the event this listener is for */
42   string clsName;
43 
44   /// Emitter order for this event listener
45   EmitterOrder order;
46 
47   /** EventListener function for this Listener */
48   EventListener listener;
49 
50   /** Utility variant caller for converting event type */
51   void delegate(Variant v) func;
52 
53   this(string clsName, EmitterOrder order, void delegate(Variant v) func) {
54     this.clsName = clsName;
55     this.func = func;
56   }
57 }
58 
59 /**
60   The Listenable template is a virtual implementation which handles the listener
61   UDAs, storing them within a local "listeners" mapping.
62 */
63 mixin template Listenable() {
64   ListenerObject[]  listeners;
65   
66   /// Load all listeners.
67   void loadListeners(T)() {
68     // TODO: make this cleaner 
69     foreach (mem; __traits(allMembers, T)) {
70       foreach(attr; __traits(getAttributes, __traits(getMember, T, mem))) {
71         static if (__traits(hasMember, attr, "clsName")) {
72           this.registerListener(new ListenerObject(attr.clsName, attr.order, (v) {
73             attr.func(v, mixin("&(cast(T)this)." ~ mem));
74           }));
75         }
76       }
77     }
78   }
79 
80   /// Registers a listener from a ListenerObject
81   void registerListener(ListenerObject obj) {
82     this.listeners ~= obj;
83   }
84 }