1 // Not actually part of forms, but is needed.
2 // This code is public domain.
3 
4 /// Event handling.
5 module dfl.event;
6 
7 import dfl.internal.dlib;
8 import std.functional;
9 
10 
11 // Create an event handler; old style.
12 deprecated template Event(TArgs : EventArgs = EventArgs)
13 {
14 	alias Event!(Object, TArgs) Event;
15 }
16 
17 
18 /** Managing event handlers.
19     Params:
20 		T1 = the sender type.
21 		T2 = the event arguments type.
22 **/
23 template Event(T1, T2) // docmain
24 {
25 	/// Managing event handlers.
26 	struct Event // docmain
27 	{
28 		alias void delegate(T1, T2) Handler; /// Event handler type.
29 		
30 		
31 		/// Add an event handler with the exact type.
32 		void addHandlerExact(Handler handler)
33 		in
34 		{
35 			assert(handler);
36 		}
37 		body
38 		{
39 			if(!_array.length)
40 			{
41 				_array = new Handler[2];
42 				_array[1] = handler;
43 				unsetHot();
44 			}
45 			else
46 			{
47 				if(!isHot())
48 				{
49 					_array ~= handler;
50 				}
51 				else // Hot.
52 				{
53 					_array = _array ~ (&handler)[0 .. 1]; // Force duplicate.
54 					unsetHot();
55 				}
56 			}
57 		}
58 		
59 		
60 		/// Add an event handler with parameter contravariance.
61 		void addHandler(TDG)(TDG handler)
62 		in
63 		{
64 			assert(handler);
65 		}
66 		body
67 		{
68 			mixin _validateHandler!(TDG);
69 			
70 			addHandlerExact(cast(Handler)toDelegate(handler));
71 		}
72 		
73 		
74 		/// Shortcut for addHandler().
75 		void opCatAssign(TDG)(TDG handler)
76 		{
77 			addHandler(toDelegate(handler));
78 		}
79 		
80 		
81 		/// Remove the specified event handler with the exact Handler type.
82 		void removeHandlerExact(Handler handler)
83 		{
84 			if(!_array.length)
85 				return;
86 			
87 			size_t iw;
88 			for(iw = 1; iw != _array.length; iw++)
89 			{
90 				if(handler == _array[iw])
91 				{
92 					if(iw == 1 && _array.length == 2)
93 					{
94 						_array = null;
95 						break;
96 					}
97 					
98 					if(iw == _array.length - 1)
99 					{
100 						_array[iw] = null;
101 						_array = _array[0 .. iw];
102 						break;
103 					}
104 					
105 					if(!isHot())
106 					{
107 						_array[iw] = _array[_array.length - 1];
108 						_array[_array.length - 1] = null;
109 						_array = _array[0 .. _array.length - 1];
110 					}
111 					else // Hot.
112 					{
113 						_array = _array[0 .. iw] ~ _array[iw + 1 .. _array.length]; // Force duplicate.
114 						unsetHot();
115 					}
116 					break;
117 				}
118 			}
119 		}
120 		
121 		
122 		/// Remove the specified event handler with parameter contravariance.
123 		void removeHandler(TDG)(TDG handler)
124 		{
125 			mixin _validateHandler!(TDG);
126 			
127 			removeHandlerExact(cast(Handler)toDelegate(handler));
128 		}
129 		
130 		
131 		/// Fire the event handlers.
132 		void opCall(T1 v1, T2 v2)
133 		{
134 			if(!_array.length)
135 				return;
136 			setHot();
137 			
138 			Handler[] local;
139 			local = _array[1 .. _array.length];
140 			foreach(Handler handler; local)
141 			{
142 				handler(v1, v2);
143 			}
144 			
145 			if(!_array.length)
146 				return;
147 			unsetHot();
148 		}
149 		
150 		
151 		///
152 		int opApply(int delegate(Handler) dg)
153 		{
154 			if(!_array.length)
155 				return 0;
156 			setHot();
157 			
158 			int result = 0;
159 			
160 			Handler[] local;
161 			local = _array[1 .. _array.length];
162 			foreach(Handler handler; local)
163 			{
164 				result = dg(handler);
165 				if(result)
166 					break;
167 			}
168 			
169 			if(_array.length)
170 				unsetHot();
171 			
172 			return result;
173 		}
174 		
175 		
176 		///
177 		@property bool hasHandlers() pure nothrow // getter
178 		{
179 			return _array.length > 1;
180 		}
181 		
182 		
183 		// Use opApply and hasHandlers instead.
184 		deprecated @property Handler[] handlers() pure nothrow // getter
185 		{
186 			if(!hasHandlers)
187 				return null;
188 			try
189 			{
190 				return _array[1 .. _array.length].dup; // Because _array can be modified. Function is deprecated anyway.
191 			}
192 			catch (DThrowable e)
193 			{
194 				return null;
195 			}
196 		}
197 		
198 		
199 		private:
200 		Handler[] _array; // Not what it seems.
201 		
202 		
203 		void setHot()
204 		{
205 			assert(_array.length);
206 			_array[0] = cast(Handler)&setHot; // Non-null, GC friendly.
207 		}
208 		
209 		
210 		void unsetHot()
211 		{
212 			assert(_array.length);
213 			_array[0] = null;
214 		}
215 		
216 		
217 		Handler isHot()
218 		{
219 			assert(_array.length);
220 			return _array[0];
221 		}
222 		
223 		
224 		// Thanks to Tomasz "h3r3tic" Stachowiak for his assistance.
225 		template _validateHandler(TDG)
226 		{
227 			static assert(is(typeof(toDelegate(TDG.init))), "DFL: Event handler must be a callable");
228 			
229 			alias ParameterTypeTuple!(TDG) TDGParams;
230 			static assert(TDGParams.length == 2, "DFL: Event handler needs exactly 2 parameters");
231 			
232 			static if(is(TDGParams[0] : Object))
233 			{
234 				static assert(is(T1: TDGParams[0]), "DFL: Event handler parameter 1 type mismatch");
235 			}
236 			else
237 			{
238 				static assert(is(T1 == TDGParams[0]), "DFL: Event handler parameter 1 type mismatch");
239 			}
240 			
241 			static if(is(TDGParams[1] : Object))
242 			{
243 				static assert(is(T2 : TDGParams[1]), "DFL: Event handler parameter 2 type mismatch");
244 			}
245 			else
246 			{
247 				static assert(is(T2 == TDGParams[1]), "DFL: Event handler parameter 2 type mismatch");
248 			}
249 		}
250 	}
251 }
252 
253 
254 /// Base event arguments.
255 class EventArgs // docmain
256 {
257 	/+
258 	private static byte[] buf;
259 	private import std.gc; // <-- ...
260 	
261 	
262 	new(uint sz)
263 	{
264 		void* result;
265 		
266 		// synchronized // Slows it down a lot.
267 		{
268 			if(sz > buf.length)
269 				buf = new byte[100 + sz];
270 			
271 			result = buf[0 .. sz];
272 			buf = buf[sz .. buf.length];
273 		}
274 		
275 		// std.gc.addRange(result, result + sz); // So that it can contain pointers.
276 		return result;
277 	}
278 	+/
279 	
280 	
281 	/+
282 	delete(void* p)
283 	{
284 		std.gc.removeRange(p);
285 	}
286 	+/
287 	
288 	
289 	//private static const EventArgs _e;
290 	private static EventArgs _e;
291 	
292 	
293 	static this()
294 	{
295 		_e = new EventArgs;
296 	}
297 	
298 	
299 	/// Property: get a reusable, _empty EventArgs.
300 	static @property EventArgs empty() nothrow // getter
301 	{
302 		return _e;
303 	}
304 }
305 
306 
307 // Simple event handler.
308 alias Event!(Object, EventArgs) EventHandler; // deprecated
309 
310 
311 ///
312 class ThreadExceptionEventArgs: EventArgs
313 {
314 	///
315 	// The exception that occured.
316 	this(DThrowable theException) pure nothrow
317 	{
318 		except = theException;
319 	}
320 	
321 	
322 	///
323 	final @property DThrowable exception() pure nothrow // getter
324 	{
325 		return except;
326 	}
327 	
328 	
329 	private:
330 	DThrowable except;
331 }
332