1 /*******************************************************************************
2  * Handler type traits and operations
3  * 
4  * Copyright: © 2019, SHOO
5  * License: [BSL-1.0](http://boost.org/LICENSE_1_0.txt).
6  * Author: SHOO
7  */
8 module cushion.handler;
9 
10 import std.traits, std.range, std.array, std.container;
11 
12 /*******************************************************************************
13  * Judge traits of Handler
14  */
15 enum bool isHandler(Handler) = __traits(compiles,
16 {
17 	Handler handler = void;
18 	HandlerParameters!Handler args = void;
19 	.call(handler, args);
20 });
21 
22 ///
23 @system unittest
24 {
25 	static struct CallableStruct { void opCall(){} }
26 	static class CallableClass { void opCall(){} }
27 	
28 	static assert(isHandler!(void function()));
29 	static assert(isHandler!(void delegate()));
30 	static assert(isHandler!(CallableClass));
31 	static assert(isHandler!(CallableStruct));
32 	static assert(isHandler!(void function()[]));
33 	static assert(isHandler!(void delegate()[]));
34 	static assert(isHandler!(CallableStruct[]));
35 	static assert(isHandler!(CallableClass[]));
36 	void delegate(Exception)[] handler = void;
37 	static assert(isHandler!(void delegate(Exception)[]));
38 }
39 
40 @safe unittest
41 {
42 	import std.container.array, std.container.slist, std.meta;
43 	
44 	static struct CallableStruct { void opCall(){} }
45 	static class CallableClass { void opCall(){} }
46 	
47 	static foreach (Type; AliasSeq!(
48 		void function(), void delegate(), CallableStruct, CallableClass))
49 	{
50 		static assert(isHandler!(Type));
51 		static assert(isHandler!(Type[]));
52 		static assert(isHandler!(Array!Type));
53 		static assert(isHandler!(SList!Type));
54 	}
55 }
56 
57 
58 /*******************************************************************************
59  * Judge traits of Handler for operation of adding
60  */
61 enum bool isHandlerAddable(Handler, Func) = __traits(compiles,
62 {
63 	Handler handler;
64 	Func func = void;
65 	.add(handler, func);
66 	.remove(handler, func);
67 	.clear(handler);
68 });
69 
70 ///
71 @safe unittest
72 {
73 	static struct CallableStruct { void opCall(){} }
74 	static class CallableClass { void opCall(){} }
75 	
76 	static assert(isHandlerAddable!(void function()[], void function()));
77 	static assert(isHandlerAddable!(void delegate()[], void delegate()));
78 	static assert(isHandlerAddable!(CallableStruct[],  CallableStruct));
79 	static assert(isHandlerAddable!(CallableClass[],   CallableClass));
80 	static assert(isHandlerAddable!(void delegate()[], void function()));
81 	static assert(isHandlerAddable!(void delegate()[], CallableStruct));
82 	static assert(isHandlerAddable!(void delegate()[], CallableClass));
83 }
84 
85 @safe unittest
86 {
87 	import std.container.array, std.container.slist, std.container.dlist, std.meta;
88 	static struct CallableStruct { void opCall(){} }
89 	static class CallableClass { void opCall(){} }
90 	
91 	static foreach (Type; AliasSeq!(
92 		void function(), void delegate(), CallableStruct, CallableClass))
93 	{
94 		static assert(!isHandlerAddable!(Type, void function()));
95 		static assert(!isHandlerAddable!(Type, void delegate()));
96 		static assert(!isHandlerAddable!(Type, CallableStruct));
97 		static assert(!isHandlerAddable!(Type, CallableClass));
98 	}
99 	
100 	static foreach (Type; AliasSeq!(
101 		void function(), void delegate(), CallableStruct, CallableClass))
102 	{
103 		static assert(isHandlerAddable!(Type[], Type));
104 		static assert(isHandlerAddable!(SList!Type, Type));
105 		static assert(isHandlerAddable!(DList!Type, Type));
106 	}
107 }
108 
109 /*******************************************************************************
110  * Judge traits of Handler for operation of assign
111  */
112 enum bool isHandlerAssignable(Handler, Func) = __traits(compiles,
113 {
114 	Handler handler;
115 	Func func = void;
116 	.set(handler, func);
117 	.clear(handler);
118 });
119 
120 ///
121 @safe unittest
122 {
123 	static assert(isHandlerAssignable!(void function(), void function()));
124 	static assert(!isHandlerAssignable!(void function(), void delegate()));
125 	static assert(isHandlerAssignable!(void function()[], void function()));
126 	static assert(!isHandlerAssignable!(void function()[], void delegate()));
127 	static assert(isHandlerAssignable!(void delegate(), void delegate()));
128 	static assert(isHandlerAssignable!(void delegate(), void function()));
129 	static assert(isHandlerAssignable!(void delegate()[], void delegate()));
130 	static assert(isHandlerAssignable!(void delegate()[], void function()));
131 	
132 	static assert(!isHandlerAssignable!(void function(), int));
133 	static assert(!isHandlerAssignable!(void function()[], int));
134 	static assert(!isHandlerAssignable!(void delegate(), int));
135 	static assert(!isHandlerAssignable!(void delegate()[], int));
136 }
137 
138 /*******************************************************************************
139  * Parameter of Handler
140  */
141 template HandlerParameters(Handler)
142 {
143 	static if (isCallable!Handler)
144 	{
145 		alias HandlerParameters = Parameters!Handler;
146 	}
147 	else static if (isIterableHandler!Handler)
148 	{
149 		alias HandlerParameters = Parameters!(ForeachType!Handler);
150 	}
151 	else static assert(0);
152 }
153 
154 ///
155 @safe unittest
156 {
157 	import std.meta;
158 	static assert(is(HandlerParameters!(void function(int)) == AliasSeq!int));
159 	static assert(is(HandlerParameters!(void function(int)[]) == AliasSeq!int));
160 	static assert(is(HandlerParameters!(void delegate(int)) == AliasSeq!int));
161 	static assert(is(HandlerParameters!(void delegate(int)[]) == AliasSeq!int));
162 }
163 
164 
165 /*******************************************************************************
166  * ReturnTypeOf of Handler
167  */
168 template HandlerReturnType(Handler)
169 {
170 	static if (isCallable!Handler)
171 	{
172 		alias HandlerReturnType = ReturnType!Handler;
173 	}
174 	else static if (isIterableHandler!Handler)
175 	{
176 		alias HandlerReturnType = ReturnType!(ForeachType!Handler);
177 	}
178 	else static assert(0);
179 }
180 
181 ///
182 @safe unittest
183 {
184 	static assert(is(HandlerReturnType!(int function()) == int));
185 	static assert(is(HandlerReturnType!(int function()[]) == int));
186 	static assert(is(HandlerReturnType!(int delegate()) == int));
187 	static assert(is(HandlerReturnType!(int delegate()[]) == int));
188 }
189 
190 
191 package(cushion):
192 
193 private template isIterableHandler(Handler)
194 {
195 	static if (isIterable!Handler && isCallable!(ForeachType!Handler))
196 	{
197 		enum bool isIterableHandler = true;
198 	}
199 	else
200 	{
201 		enum bool isIterableHandler = false;
202 	}
203 }
204 
205 @safe unittest
206 {
207 	static assert(!isIterableHandler!(void function()));
208 	static assert(isIterableHandler!(void function()[]));
209 	static assert(!isIterableHandler!(void delegate()));
210 	static assert(isIterableHandler!(void delegate()[]));
211 }
212 
213 
214 /*#*****************************************************************************
215  * 
216  */
217 pragma(inline) void call(Handler, Args...)(ref Handler handler, Args args) @trusted
218 {
219 	static if (isCallable!Handler && is(ReturnType!Handler == void))
220 	{
221 		static if (__traits(compiles, {if(handler){}}))
222 		{
223 			if (handler)
224 				handler(args);
225 		}
226 		else
227 		{
228 			handler(args);
229 		}
230 	}
231 	else static if (isIterableHandler!Handler
232 	             && is(HandlerReturnType!Handler == void))
233 	{
234 		foreach (ref h; handler)
235 		{
236 			static if (__traits(compiles, {if(h){}}))
237 			{
238 				if (h)
239 					h(args);
240 			}
241 			else
242 			{
243 				h(args);
244 			}
245 		}
246 	}
247 	else static assert(0);
248 }
249 
250 
251 /*#*****************************************************************************
252  * 
253  */
254 pragma(inline) void add(Handler, Func)(ref Handler handler, Func func) @trusted
255 {
256 	static if (__traits(compiles, {
257 		handler ~= func;
258 	}))
259 	{
260 		handler ~= func;
261 	}
262 	else static if (__traits(hasMember, handler, "insert") && __traits(compiles, {
263 		handler.insert(func);
264 	}))
265 	{
266 		handler.insert(func);
267 	}
268 	else static if (__traits(hasMember, handler, "connect") && __traits(compiles, {
269 		handler.connect(func);
270 	}))
271 	{
272 		handler.connect(func);
273 	}
274 	else static if (__traits(compiles, {
275 		import std.functional: toDelegate;
276 		handler ~= toDelegate(func);
277 	}))
278 	{
279 		import std.functional: toDelegate;
280 		handler ~= toDelegate(func);
281 	}
282 	else static if (__traits(hasMember, handler, "insert") && __traits(compiles, {
283 		import std.functional: toDelegate;
284 		handler.insert(toDelegate(func));
285 	}))
286 	{
287 		import std.functional: toDelegate;
288 		handler.insert(toDelegate(func));
289 	}
290 	else static if (__traits(hasMember, handler, "connect") && __traits(compiles, {
291 		import std.functional: toDelegate;
292 		handler.connect(toDelegate(func));
293 	}))
294 	{
295 		import std.functional: toDelegate;
296 		handler.connect(toDelegate(func));
297 	}
298 	else static assert(0);
299 }
300 
301 
302 /*#*****************************************************************************
303  * 
304  */
305 pragma(inline) void remove(Handler, Func)(ref Handler handler, Func func) @trusted
306 {
307 	import std.algorithm;
308 	static if (__traits(hasMember, handler, "remove") && __traits(compiles, {
309 		__traits(getMember, handler, "remove")(func);
310 	}))
311 	{
312 		__traits(getMember, handler, "remove")(func);
313 	}
314 	else static if (__traits(hasMember, handler, "disconnect") && __traits(compiles, {
315 		handler.disconnect(func);
316 	}))
317 	{
318 		handler.disconnect(func);
319 	}
320 	else static if (__traits(compiles, {
321 		handler.linearRemoveElement(func);
322 	}))
323 	{
324 		handler.linearRemoveElement(func);
325 	}
326 	else static if (__traits(compiles, {
327 		handler = std.algorithm.remove!(a => a is func)(handler);
328 	}))
329 	{
330 		handler = std.algorithm.remove!(a => a is func)(handler);
331 	}
332 	else static if (__traits(hasMember, handler, "remove") && __traits(compiles, {
333 		import std.functional: toDelegate;
334 		__traits(getMember, handler, "remove")(toDelegate(func));
335 	}))
336 	{
337 		import std.functional: toDelegate;
338 		__traits(getMember, handler, "remove")(toDelegate(func));
339 	}
340 	else static if (__traits(hasMember, handler, "disconnect") && __traits(compiles, {
341 		import std.functional: toDelegate;
342 		handler.disconnect(toDelegate(func));
343 	}))
344 	{
345 		import std.functional: toDelegate;
346 		handler.disconnect(toDelegate(func));
347 	}
348 	else static if (__traits(compiles, {
349 		import std.functional: toDelegate;
350 		handler.linearRemoveElement(toDelegate(func));
351 	}))
352 	{
353 		import std.functional: toDelegate;
354 		handler.linearRemoveElement(toDelegate(func));
355 	}
356 	else static if (__traits(compiles, {
357 		import std.functional: toDelegate;
358 		auto dg = toDelegate(func);
359 		handler = std.algorithm.remove!(a => a is dg)(handler);
360 	}))
361 	{
362 		import std.functional: toDelegate;
363 		auto dg = toDelegate(func);
364 		handler = std.algorithm.remove!(a => a is dg)(handler);
365 	}
366 	else static assert(0);
367 }
368 
369 
370 /*#*****************************************************************************
371  * 
372  */
373 pragma(inline) void clear(Handler)(ref Handler handler) @trusted
374 {
375 	static if (__traits(hasMember, handler, "clear") && __traits(compiles, {
376 		__traits(getMember, handler, "clear")();
377 	}))
378 	{
379 		__traits(getMember, handler, "clear")();
380 	}
381 	else static if (!is(Handler == class)
382 		&& !is(Handler == interface)
383 		&& (!isPointer!Handler || isFunctionPointer!Handler)
384 		&& __traits(compiles, { handler = Handler.init; }))
385 	{
386 		handler = Handler.init;
387 	}
388 	else static assert(0);
389 }
390 
391 
392 
393 /*#*****************************************************************************
394  * 
395  */
396 pragma(inline) void set(Handler, Func)(ref Handler handler, Func func) @trusted
397 {
398 	static if (__traits(compiles, {
399 		handler = func;
400 	}))
401 	{
402 		handler = func;
403 	}
404 	else static if (__traits(compiles, {
405 		import std.functional: toDelegate;
406 		handler = toDelegate(func);
407 	}))
408 	{
409 		import std.functional: toDelegate;
410 		handler = toDelegate(func);
411 	}
412 	else static if (__traits(compiles, {
413 		handler.clear();
414 		handler.add(func);
415 	}))
416 	{
417 		handler.clear();
418 		handler.add(func);
419 	}
420 	else static assert(0);
421 }
422 
423 @safe unittest
424 {
425 	void function() foo1;
426 	void function()[] foo2;
427 	void delegate() foo3;
428 	void delegate()[] foo4;
429 }
430 
431 private void linearRemoveElement(E)(ref Array!E ary, E e)
432 {
433 	import std.algorithm;
434 	auto r = std.algorithm.remove(ary[], e);
435 	ary.removeBack(ary.length - r.length);
436 }