1 module events.event;
2 import events.eventargs;
3 
4 /**
5 	An easy alias for the EventHandler signature.
6 */
7 //alias EventHandler = void delegate(void* sender, EventArgs data);
8 
9 /**
10 	An event.
11 	To add event handlers to the event use ~= or += followed by your event delegate.
12 	(use EventHandler for an easy signature for the delegate)
13 
14 	The delegate should take an void* sender and EventArgs argument.
15 
16 	Use -= to remove an event handler delegate from the event.
17 */
18 public class Event(EventData) {
19 private:
20 	alias EventHandler = void delegate(void* sender, EventData data);
21 	EventHandler[] handlers;
22 	
23 public:
24 
25 	/**
26 		Gets the amount of handlers that are bound to this event
27 	*/
28 	size_t count() {
29 		return handlers.length;
30 	}
31 
32 	/**
33 		Clears all handlers from the event
34 	*/
35 	void clear() {
36 		handlers.length = 0;
37 	}
38 
39 	/**
40 		Call all event handlers bound to this event
41 	*/
42 	void opCall(void* sender, EventData data) {
43 		foreach(EventHandler handler; handlers) {
44 			handler(sender, data);
45 		}
46 	}
47 
48 	/**
49 		Call all event handlers bound to this event
50 	*/
51 	void opCall(void* sender) {
52 		foreach(EventHandler handler; handlers) {
53 			handler(sender, EventData.init);
54 		}
55 	}
56 
57 	/**
58 		Add a new handler
59 	*/
60 	deprecated("C# style event adding is deprecated, please use ~= instead.")
61 	Event opOpAssign(string op : "+")(EventHandler handler) {
62 		handlers.length++;
63 		handlers[$-1] = handler;
64 		return this;
65 	}
66 
67 	/**
68 		Add a new handler
69 	*/
70 	Event opOpAssign(string op : "~")(EventHandler handler) {
71 		handlers.length++;
72 		handlers[$-1] = handler;
73 		return this;
74 	}
75 
76 	/**
77 		Deletes a handler
78 	*/
79 	Event opOpAssign(string op : "-")(EventHandler handler) {
80 		int remove = 0;
81 		for (int i = 0; i < handlers.length; i++) {
82 			if (handlers[i] == handler) {
83 				handlers[i] = null;
84 				remove++;
85 			}
86 
87 			if (remove == handlers.length) break;
88 
89 			if (handlers[i-1] is null) {
90 				handlers[i-1] = handlers[i];
91 				handlers[i] = null;
92 			}
93 		}
94 		handlers.length -= remove;
95 		return this;
96 	}
97 }
98 
99 /**
100 	Test the creation and execution of an event
101 */
102 unittest {
103 
104 	struct TestEventData { string name; }
105 	bool wasRun;
106 
107 	// Test creation
108 	auto eventHandler = (void* sender, TestEventData args) {
109 		assert(args.name == "test", "Expected value of event args to be \"Test\"");
110 		wasRun = true;
111 	};
112 
113 	Event!TestEventData testEvent = new Event!TestEventData;
114 	testEvent ~= eventHandler;
115 
116 	// Test execution
117 	testEvent(null, TestEventData("test"));
118 	assert(wasRun, "Expected event to be executed!");
119 
120 	// Test deletion of event handler
121 	testEvent -= eventHandler;
122 	assert(testEvent.count == 0, "Expected event to have no handlers!");
123 }
124 
125 /**
126 	A basic event that takes an EventArgs as arguments
127 */
128 public class BasicEvent : Event!EventArgs { }
129 
130 /**
131 	Test the creation and execution of a basic event
132 */
133 unittest {
134 	class TestEventArgs : EventArgs {
135 		string name;
136 
137 		this(string name) {
138 			this.name = name;
139 		}
140 	}
141 	bool wasRun;
142 
143 	// Test creation
144 	auto eventHandler = (void* sender, EventArgs args) {
145 		TestEventArgs testArgs = cast(TestEventArgs)args;
146 		assert(testArgs.name == "test", "Expected value of event args to be \"Test\"");
147 		wasRun = true;
148 	};
149 
150 	BasicEvent testEvent = new BasicEvent;
151 	testEvent ~= eventHandler;
152 
153 	// Test execution
154 	testEvent(null, new TestEventArgs("test"));
155 	assert(wasRun, "Expected event to be executed!");
156 
157 	// Test deletion of event handler
158 	testEvent -= eventHandler;
159 	assert(testEvent.count == 0, "Expected event to have no handlers!");
160 }