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 }