/signals.d

http://github.com/AndrejMitrovic/cairoDSamples · D · 1116 lines · 648 code · 73 blank · 395 comment · 102 complexity · 7ef5e805aea15322a18f845f502458d4 MD5 · raw file

  1. // Written in the D programming language.
  2. /**
  3. * Signals and Slots are an implementation of the Observer Pattern.
  4. * Essentially, when a Signal is emitted, a list of connected Observers
  5. * (called slots) are called.
  6. *
  7. * There have been several D implementations of Signals and Slots.
  8. * This version makes use of several new features in D, which make
  9. * using it simpler and less error prone. In particular, it is no
  10. * longer necessary to instrument the slots.
  11. *
  12. * References:
  13. * $(LINK2 http://scottcollins.net/articles/a-deeper-look-at-_signals-and-slots.html, A Deeper Look at Signals and Slots)$(BR)
  14. * $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR)
  15. * $(LINK2 http://en.wikipedia.org/wiki/Signals_and_slots, Wikipedia)$(BR)
  16. * $(LINK2 http://boost.org/doc/html/$(SIGNALS).html, Boost Signals)$(BR)
  17. * $(LINK2 http://doc.trolltech.com/4.1/signalsandslots.html, Qt)$(BR)
  18. *
  19. * There has been a great deal of discussion in the D newsgroups
  20. * over this, and several implementations:
  21. *
  22. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/signal_slots_library_4825.html, signal slots library)$(BR)
  23. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Signals_and_Slots_in_D_42387.html, Signals and Slots in D)$(BR)
  24. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dynamic_binding_--_Qt_s_Signals_and_Slots_vs_Objective-C_42260.html, Dynamic binding -- Qt's Signals and Slots vs Objective-C)$(BR)
  25. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dissecting_the_SS_42377.html, Dissecting the SS)$(BR)
  26. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/dwt/about_harmonia_454.html, about harmonia)$(BR)
  27. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/1502.html, Another event handling module)$(BR)
  28. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/41825.html, Suggestion: signal/slot mechanism)$(BR)
  29. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/13251.html, Signals and slots?)$(BR)
  30. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/10714.html, Signals and slots ready for evaluation)$(BR)
  31. * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/1393.html, Signals & Slots for Walter)$(BR)
  32. * $(LINK2 http://www.digitalmars.com/d/archives/28456.html, Signal/Slot mechanism?)$(BR)
  33. * $(LINK2 http://www.digitalmars.com/d/archives/19470.html, Modern Features?)$(BR)
  34. * $(LINK2 http://www.digitalmars.com/d/archives/16592.html, Delegates vs interfaces)$(BR)
  35. * $(LINK2 http://www.digitalmars.com/d/archives/16583.html, The importance of component programming (properties, signals and slots, etc))$(BR)
  36. * $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR)
  37. *
  38. * Bugs:
  39. * Not safe for multiple threads operating on the same signals
  40. * or slots.
  41. *
  42. * Safety of handlers is not yet enforced
  43. * Macros:
  44. * WIKI = Phobos/StdSignals
  45. * SIGNALS=signals
  46. *
  47. * Copyright: Copyright Digital Mars 2000 - 2009.
  48. * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
  49. * Authors: $(WEB digitalmars.com, Walter Bright),
  50. * Johannes Pfau
  51. */
  52. /* Copyright Digital Mars 2000 - 2009.
  53. * Distributed under the Boost Software License, Version 1.0.
  54. * (See accompanying file LICENSE_1_0.txt or copy at
  55. * http://www.boost.org/LICENSE_1_0.txt)
  56. */
  57. //~ module signals;
  58. import std.algorithm; //find
  59. import std.container; //SList
  60. import std.functional; //toDelegate
  61. import std.range; //take
  62. import std.traits; //isPointer, isSafe
  63. //Bug 4536
  64. private template Init(T...)
  65. {
  66. T Init;
  67. }
  68. template isHandlerDelegate(T, Types...)
  69. {
  70. static if(is(T == delegate))
  71. {
  72. enum bool isHandlerDelegate = (is(typeof(T.init(Init!(Types))))
  73. && (is(ReturnType!(T) == void)
  74. || is(ReturnType!(T) == bool)));
  75. }
  76. else
  77. {
  78. enum bool isHandlerDelegate = false;
  79. }
  80. }
  81. template isHandlerFunction(T, Types...)
  82. {
  83. static if(isPointer!(T))
  84. {
  85. enum bool isHandlerFunction = (isPointer!(T) && is(pointerTarget!(T) == function)
  86. && is(typeof(T.init(Init!(Types))))
  87. && (is(ReturnType!(T) == void)
  88. || is(ReturnType!(T) == bool)));
  89. }
  90. else
  91. {
  92. enum bool isHandlerFunction = false;
  93. }
  94. }
  95. template isHandlerStruct(T, Types...)
  96. {
  97. static if(isPointer!(T))
  98. {
  99. enum bool isHandlerStruct = (is(pointerTarget!(T) == struct)
  100. //&& (isSafe!(pointerTarget!(T).init))
  101. && is(typeof(pointerTarget!(T).init.opCall(Init!(Types))))
  102. && (is(ReturnType!(T) == void)
  103. || is(ReturnType!(T) == bool)));
  104. }
  105. else
  106. {
  107. enum bool isHandlerStruct = false;
  108. }
  109. }
  110. unittest
  111. {
  112. struct tmp
  113. {
  114. @safe bool opCall() {return false;}
  115. }
  116. tmp* a = new tmp();
  117. assert(isHandlerStruct!(typeof(a)));
  118. tmp b;
  119. assert(!isHandlerStruct!(typeof(b)));
  120. }
  121. //Checking for unsafe handlers is not yet implemented
  122. /*
  123. unittest
  124. {
  125. struct tmp
  126. {
  127. bool opCall() {return false;}
  128. }
  129. tmp* a = new tmp();
  130. assert(!isHandlerStruct!(typeof(a)));
  131. tmp b;
  132. assert(!isHandlerStruct!(typeof(b)));
  133. }
  134. */
  135. template isHandlerClass(T, Types...)
  136. {
  137. enum bool isHandlerClass = (is(T == class)
  138. && is(typeof(T.init.opCall(Init!(Types))))
  139. && (is(ReturnType!(T) == void)
  140. || is(ReturnType!(T) == bool)));
  141. }
  142. template isHandler(T, Types...)
  143. {
  144. enum bool isHandler = isHandlerDelegate!(T, Types) || isHandlerFunction!(T, Types)
  145. || isHandlerClass!(T, Types) || isHandlerStruct!(T, Types);
  146. }
  147. unittest
  148. {
  149. struct tmp
  150. {
  151. @safe void opCall(){}
  152. }
  153. struct tmp2
  154. {
  155. @safe char opCall(){ return 'c';}
  156. }
  157. struct tmp3
  158. {
  159. @safe bool opCall(){ return true;}
  160. }
  161. tmp* a = new tmp();
  162. assert(isHandler!(typeof(a)));
  163. assert(!isHandler!(typeof(a), int));
  164. assert(!isHandler!(typeof(a), int, bool));
  165. assert(!isHandler!(typeof(a), int, bool, string));
  166. tmp b;
  167. assert(!isHandler!(typeof(b)));
  168. assert(!isHandler!(typeof(b), int));
  169. assert(!isHandler!(typeof(b), int, bool));
  170. assert(!isHandler!(typeof(b), int, bool, string));
  171. tmp2 c;
  172. assert(!isHandler!(typeof(c)));
  173. assert(!isHandler!(typeof(c), int));
  174. assert(!isHandler!(typeof(c), int, bool));
  175. assert(!isHandler!(typeof(c), int, bool, string));
  176. tmp3* d = new tmp3();
  177. assert(isHandler!(typeof(d)));
  178. assert(!isHandler!(typeof(d), int));
  179. assert(!isHandler!(typeof(d), int, bool));
  180. assert(!isHandler!(typeof(d), int, bool, string));
  181. }
  182. unittest
  183. {
  184. class tmp
  185. {
  186. @safe void opCall(int i){}
  187. }
  188. class tmp2
  189. {
  190. @safe char opCall(string a, bool b){ return 'c';}
  191. }
  192. class tmp3
  193. {
  194. @safe bool opCall(char b){ return true;}
  195. }
  196. tmp a = new tmp();
  197. assert(!isHandler!(typeof(a)));
  198. assert(isHandler!(typeof(a), int));
  199. assert(!isHandler!(typeof(a), int, bool));
  200. assert(!isHandler!(typeof(a), int, bool, string));
  201. tmp2 b = new tmp2();
  202. assert(!isHandler!(typeof(b)));
  203. assert(!isHandler!(typeof(b), string, bool));
  204. assert(!isHandler!(typeof(b), int, bool));
  205. assert(!isHandler!(typeof(b), int, bool, string));
  206. tmp3 c = new tmp3();
  207. assert(!isHandler!(typeof(c)));
  208. assert(isHandler!(typeof(c), char));
  209. assert(!isHandler!(typeof(c), int, bool));
  210. assert(!isHandler!(typeof(c), int, bool, string));
  211. }
  212. unittest
  213. {
  214. static @safe void test(int a, int b) {};
  215. static @safe void test2(int b) {};
  216. static @safe bool test3(int a, int b) {return true;};
  217. static @safe bool test4(int b) {return true;};
  218. assert(isHandler!(typeof(&test), int, int));
  219. assert(!isHandler!(typeof(&test)));
  220. assert(isHandler!(typeof(&test2), int));
  221. assert(!isHandler!(typeof(&test2, string)));
  222. assert(isHandler!(typeof(&test3), int, int));
  223. assert(!isHandler!(typeof(&test3), bool));
  224. assert(isHandler!(typeof(&test4), int));
  225. assert(!isHandler!(typeof(&test4)));
  226. }
  227. unittest
  228. {
  229. @safe void test(int a, int b) {};
  230. @safe void test2(int b) {};
  231. @safe bool test3(int a, int b) {return true;};
  232. @safe bool test4(int b) {return true;};
  233. assert(isHandler!(typeof(&test), int, int));
  234. assert(!isHandler!(typeof(&test)));
  235. assert(isHandler!(typeof(&test2), int));
  236. assert(!isHandler!(typeof(&test2, string)));
  237. assert(isHandler!(typeof(&test3), int, int));
  238. assert(!isHandler!(typeof(&test3), bool));
  239. assert(isHandler!(typeof(&test4), int));
  240. assert(!isHandler!(typeof(&test4)));
  241. }
  242. /**
  243. * This Signal struct is an implementation of the Observer pattern.
  244. *
  245. * All D callable types (functions, delegates, structs with opCall,
  246. * classes with opCall) can be registered with a signal. When the signal
  247. * occurs all assigned callables are called.
  248. *
  249. * Structs with opCall are only supported if they're passed by pointer. These
  250. * structs are then expected to be allocated on the heap.
  251. *
  252. * Delegates to struct instances or nested functions are supported. You
  253. * have to make sure to disconnect these delegates from the Signal before
  254. * they go out of scope though.
  255. *
  256. * The return type of the handlers must be void or bool. If the return
  257. * type is bool and the handler returns false the remaining handlers are
  258. * not called. If true is returned or the type is void the remaining
  259. * handlers are called.
  260. *
  261. * SafeD:
  262. * This Signal template can be used in safeD; all public functions
  263. * are @safe or @trusted. All handlers connected to
  264. * a signal must be @safe or @trusted. It's currently not possible to
  265. * enforce the safety of the handlers, but it will be enforced as soon
  266. * as possible.
  267. *
  268. * Examples:
  269. * -------------------------------------------------------------------
  270. * import std.stdio;
  271. * import std.signals;
  272. *
  273. * //same for classes
  274. * struct A
  275. * {
  276. * string payload;
  277. * @safe bool opCall(float f, string s)
  278. * {
  279. * writefln("A: %f:%s:%s", f, s, payload);
  280. * return true;
  281. * }
  282. * }
  283. *
  284. * @safe void testFunc(float f, string s)
  285. * {
  286. * writefln("Function: %f:%s", f, s);
  287. * }
  288. *
  289. * Signal!(float, string) onTest;
  290. *
  291. * void main()
  292. * {
  293. * A* a = new A();
  294. * a.payload = "test payload";
  295. * onTest.connect(a);
  296. * onTest ~= &testFunc;
  297. * onTest(0.123f, "first call");
  298. * }
  299. * -------------------------------------------------------------------
  300. */
  301. public struct Signal(Types...)
  302. {
  303. private:
  304. //A slot is implemented as a delegate. The slot_t is the type of the delegate.
  305. alias bool delegate(Types) slot_t;
  306. //Same as slot_t but with void return type
  307. alias void delegate(Types) void_slot_t;
  308. /* This struct stores one delegate and information whether the
  309. * delegate returns a bool or void */
  310. static struct Callable
  311. {
  312. //The void_slot_t delegate
  313. slot_t deleg;
  314. bool returnsBool = true;
  315. this(void_slot_t del)
  316. {
  317. this.deleg = cast(slot_t)del;
  318. this.returnsBool = false;
  319. }
  320. this(slot_t del)
  321. {
  322. this.deleg = del;
  323. }
  324. }
  325. SList!(Callable) handlers;
  326. /*
  327. * Get a Callable for the handler.
  328. * Handler can be a void function, void delegate, bool
  329. * function, bool delegate, class with opCall or a pointer to
  330. * a struct with opCall.
  331. */
  332. @trusted Callable getCallable(T)(T handler) if(isHandler!(T, Types))
  333. {
  334. static if(isHandlerDelegate!(T, Types) && is(ReturnType!(T) == void))
  335. {
  336. return Callable(cast(void_slot_t)handler);
  337. }
  338. else static if(isHandlerFunction!(T, Types) && is(ReturnType!(T) == void))
  339. {
  340. void delegate(Types) call = toDelegate(cast(void function(Types))handler);
  341. return Callable(call);
  342. }
  343. else static if(isHandlerDelegate!(T, Types) && is(ReturnType!(T) == bool))
  344. {
  345. return Callable(cast(slot_t)handler);
  346. }
  347. else static if(isHandlerFunction!(T, Types) && is(ReturnType!(T) == bool))
  348. {
  349. return Callable(toDelegate(cast(bool function(Types))handler));
  350. }
  351. else static if(isHandlerStruct!(T, Types))
  352. {
  353. static if(is(ReturnType!(T) == void))
  354. {
  355. return Callable(cast(void_slot_t)&handler.opCall);
  356. }
  357. else static if(is(ReturnType!(T) == bool))
  358. {
  359. return Callable(cast(slot_t)&handler.opCall);
  360. }
  361. else
  362. {
  363. static assert(false, "BUG: Internal error");
  364. }
  365. }
  366. else static if(isHandlerClass!(T, Types))
  367. {
  368. static if(is(ReturnType!(T) == void))
  369. {
  370. return Callable(cast(void_slot_t)&handler.opCall);
  371. }
  372. else static if(is(ReturnType!(T) == bool))
  373. {
  374. return Callable(cast(slot_t)&handler.opCall);
  375. }
  376. else
  377. {
  378. static assert(false, "BUG: Internal error");
  379. }
  380. }
  381. else
  382. {
  383. static assert(false, "BUG: Input type not supported. "
  384. "Please file a bug report.");
  385. }
  386. }
  387. public:
  388. /**
  389. * Set to false to disable signal emission
  390. *
  391. * Examples:
  392. * --------------------------------
  393. * bool called = false;
  394. * @safe void handler() { called = true; }
  395. * Signal!() onTest;
  396. * onTest ~= &handler;
  397. * onTest();
  398. * assert(called);
  399. * called = false;
  400. * onTest.enabled = false;
  401. * onTest();
  402. * assert(!called);
  403. * onTest.enabled = true;
  404. * onTest();
  405. * assert(called);
  406. * --------------------------------
  407. */
  408. @safe bool enabled = true;
  409. /**
  410. * Check whether a handler is already connected
  411. *
  412. * Examples:
  413. * --------------------------------
  414. * @safe void handler() {};
  415. * Signal!() onTest;
  416. * assert(!onTest.isConnected(&handler));
  417. * onTest ~= &handler;
  418. * assert(onTest.isConnected(&handler));
  419. * onTest();
  420. * --------------------------------
  421. */
  422. @trusted bool isConnected(T)(T handler) if(isHandler!(T, Types))
  423. {
  424. Callable call = getCallable(handler);
  425. return !find(handlers[], call).empty;
  426. }
  427. /**
  428. * Add a handler to the list of handlers to be called when emit() is called.
  429. * The handler is added at the end of the list.
  430. *
  431. * Throws:
  432. * Exception if handler is already registered
  433. * (Only if asserts are enabled! Does not throw
  434. * in release mode!)
  435. *
  436. * Returns:
  437. * The handler that was passed in as a paramter
  438. *
  439. * Examples:
  440. * --------------------------------
  441. * int val;
  442. * string text;
  443. * @safe void handler(int i, string t)
  444. * {
  445. * val = i;
  446. * text = t;
  447. * }
  448. *
  449. * Signal!(int, string) onTest;
  450. * onTest.connect(&handler);
  451. * onTest(1, "test");
  452. * assert(val == 1);
  453. * assert(text == "test");
  454. * --------------------------------
  455. */
  456. @trusted T connect(T)(T handler) if(isHandler!(T, Types))
  457. {
  458. Callable call = getCallable(handler);
  459. assert(find(handlers[], call).empty, "Handler is already registered!");
  460. handlers.stableInsertAfter(handlers[], call);
  461. return handler;
  462. }
  463. /**
  464. * Add a handler to the list of handlers to be called when emit() is called.
  465. * Add this handler at the top of the list, so it will be called before all
  466. * other handlers.
  467. *
  468. * Throws:
  469. * Exception if handler is already registered
  470. * (Only if asserts are enabled! Does not throw
  471. * in release mode!)
  472. *
  473. * Returns:
  474. * The handler that was passed in as a paramter
  475. *
  476. * --------------------------------
  477. * bool firstCalled, secondCalled;
  478. * @safe void handler1() {firstCalled = true;}
  479. * @safe void handler2()
  480. * {
  481. * secondCalled = true;
  482. * assert(firstCalled);
  483. * }
  484. * Signal!() onTest;
  485. * onTest ~= &handler2;
  486. * onTest.connectFirst(&handler1);
  487. * onTest();
  488. * assert(firstCalled && secondCalled);
  489. * --------------------------------
  490. */
  491. @trusted T connectFirst(T)(T handler) if(isHandler!(T, Types))
  492. {
  493. Callable call = getCallable(handler);
  494. assert(find(handlers[], call).empty, "Handler is already registered!");
  495. handlers.stableInsertFront(call);
  496. return handler;
  497. }
  498. /**
  499. * Add a handler to be called after another handler.
  500. * Params:
  501. * afterThis = The new attached handler will be called after this handler
  502. * handler = The handler to be attached
  503. *
  504. * Throws:
  505. * Exception if handler is already registered
  506. * (Only if asserts are enabled! Does not throw
  507. * in release mode!)
  508. *
  509. * Exception if afterThis is not registered
  510. * (Always, even if asserts are disabled)
  511. *
  512. * Returns:
  513. * The handler that has been connected
  514. *
  515. * Examples:
  516. * --------------------------------
  517. * bool firstCalled, secondCalled, thirdCalled;
  518. * @safe void handler1() {firstCalled = true;}
  519. * @safe void handler2()
  520. * {
  521. * secondCalled = true;
  522. * assert(firstCalled);
  523. * assert(thirdCalled);
  524. * }
  525. * @safe void handler3()
  526. * {
  527. * thirdCalled = true;
  528. * assert(firstCalled);
  529. * assert(!secondCalled);
  530. * }
  531. * Signal!() onTest;
  532. * onTest ~= &handler1;
  533. * onTest ~= &handler2;
  534. * auto h = onTest.connectAfter(&handler1, &handler3);
  535. * assert(h == &handler3);
  536. * onTest();
  537. * assert(firstCalled && secondCalled && thirdCalled);
  538. * --------------------------------
  539. */
  540. @trusted T connectAfter(T, U)(T afterThis, U handler)
  541. if(isHandler!(T, Types) && isHandler!(U, Types))
  542. {
  543. Callable after = getCallable(afterThis);
  544. Callable call = getCallable(handler);
  545. auto location = find(handlers[], after);
  546. if(location.empty)
  547. {
  548. throw new Exception("Handler 'afterThis' is not registered!");
  549. }
  550. assert(find(handlers[], call).empty, "Handler is already registered!");
  551. handlers.stableInsertAfter(take(location, 1), call);
  552. return handler;
  553. }
  554. /**
  555. * Add a handler to be called before another handler.
  556. * Params:
  557. * beforeThis = The new attached handler will be called after this handler
  558. * handler = The handler to be attached
  559. *
  560. * Throws:
  561. * Exception if handler is already registered
  562. * (Only if asserts are enabled! Does not throw
  563. * in release mode!)
  564. *
  565. * Returns:
  566. * The handler that has been connected
  567. *
  568. * Exception if beforeThis is not registered
  569. * (Always, even if asserts are disabled)
  570. *
  571. * Examples:
  572. * --------------------------------
  573. * bool firstCalled, secondCalled, thirdCalled;
  574. * @safe void handler1() {firstCalled = true;}
  575. * @safe void handler2()
  576. * {
  577. * secondCalled = true;
  578. * assert(firstCalled);
  579. * assert(!thirdCalled);
  580. * }
  581. * @safe void handler3()
  582. * {
  583. * thirdCalled = true;
  584. * assert(firstCalled);
  585. * assert(secondCalled);
  586. * }
  587. * Signal!() onTest;
  588. * onTest ~= &handler1;
  589. * onTest ~= &handler3;
  590. * onTest.connectBefore(&handler3, &handler2);
  591. * onTest();
  592. * assert(firstCalled && secondCalled && thirdCalled);
  593. * --------------------------------
  594. */
  595. @trusted T connectBefore(T, U)(T beforeThis, U handler)
  596. if(isHandler!(T, Types) && isHandler!(U, Types))
  597. {
  598. Callable before = getCallable(beforeThis);
  599. Callable call = getCallable(handler);
  600. auto location = find(handlers[], before);
  601. if(location.empty)
  602. {
  603. throw new Exception("Handler 'beforeThis' is not registered!");
  604. }
  605. assert(find(handlers[], call).empty, "Handler is already registered!");
  606. //not exactly fast
  607. uint length = walkLength(handlers[]);
  608. uint pos = walkLength(location);
  609. uint new_location = length - pos;
  610. location = handlers[];
  611. if(new_location == 0)
  612. handlers.stableInsertFront(call);
  613. else
  614. handlers.stableInsertAfter(take(location, new_location), call);
  615. return handler;
  616. }
  617. /**
  618. * Remove a handler from the list of handlers to be called when emit() is called.
  619. *
  620. * Throws:
  621. * Exception if handler is not registered
  622. * (Always, even if asserts are disabled)
  623. *
  624. * Returns:
  625. * The handler that has been disconnected
  626. *
  627. * Examples:
  628. * --------------------------------
  629. * @safe void handler() {};
  630. * Signal!() onTest;
  631. * onTest.connect(&handler);
  632. * onTest.disconnect(&handler);
  633. * onTest.connect(&handler);
  634. * onTest();
  635. * --------------------------------
  636. */
  637. @trusted T disconnect(T)(T handler) if(isHandler!(T, Types))
  638. {
  639. Callable call = getCallable(handler);
  640. auto pos = find(handlers[], call);
  641. if(pos.empty)
  642. {
  643. throw new Exception("Handler is not connected");
  644. }
  645. handlers.stableLinearRemove(take(pos, 1));
  646. return handler;
  647. }
  648. /**
  649. * Remove all handlers from the signal
  650. *
  651. * Examples:
  652. * --------------------------------
  653. * @safe void handler() {};
  654. * Signal!() onTest;
  655. * assert(onTest.calculateLength() == 0);
  656. * onTest.connect(&handler);
  657. * assert(onTest.calculateLength() == 1);
  658. * onTest.clear();
  659. * assert(onTest.calculateLength() == 0);
  660. * onTest();
  661. * --------------------------------
  662. */
  663. @trusted void clear()
  664. {
  665. handlers.clear();
  666. }
  667. /**
  668. * Calculate the number of registered handlers
  669. *
  670. * Complexity: $(BIGOH n)
  671. *
  672. * Examples:
  673. * --------------------------------
  674. * @safe void handler() {};
  675. * @safe void handler2() {};
  676. * Signal!() onTest;
  677. * assert(onTest.calculateLength() == 0);
  678. * onTest.connect(&handler);
  679. * assert(onTest.calculateLength() == 1);
  680. * onTest.connect(&handler2);
  681. * assert(onTest.calculateLength() == 2);
  682. * onTest.clear();
  683. * assert(onTest.calculateLength() == 0);
  684. * onTest();
  685. * --------------------------------
  686. */
  687. @trusted uint calculateLength()
  688. {
  689. return walkLength(handlers[]);
  690. }
  691. /**
  692. * Just like Signal.connect()
  693. */
  694. @safe T opOpAssign(string op, T)(T rhs) if(op == "~" && isHandler!(T, Types))
  695. {
  696. return connect!(T)(rhs);
  697. }
  698. /**
  699. * Call the connected handlers as explained in the documentation
  700. * for the signal struct.
  701. *
  702. * Throws:
  703. * Exceptions thrown in the signal handlers
  704. *
  705. * Examples:
  706. * --------------------------------
  707. * @safe void handler() {};
  708. * Signal!() onTest;
  709. * onTest.connect(&handler);
  710. * onTest.emit();
  711. * --------------------------------
  712. */
  713. @trusted void emit(Types params)
  714. {
  715. if(this.enabled)
  716. {
  717. foreach(callable; handlers[])
  718. {
  719. if(callable.returnsBool)
  720. {
  721. slot_t del = cast(slot_t)callable.deleg;
  722. if(!del(params))
  723. return;
  724. }
  725. else
  726. {
  727. void_slot_t del = cast(void_slot_t)callable.deleg;
  728. del(params);
  729. }
  730. }
  731. }
  732. }
  733. /**
  734. * Just like emit()
  735. */
  736. @trusted void opCall(Types params)
  737. {
  738. emit(params);
  739. }
  740. }
  741. //unit tests
  742. unittest
  743. {
  744. int val;
  745. string text;
  746. @safe void handler(int i, string t)
  747. {
  748. val = i;
  749. text = t;
  750. }
  751. @safe static void handler2(int i, string t)
  752. {
  753. }
  754. Signal!(int, string) onTest;
  755. onTest.connect(&handler);
  756. onTest.connect(&handler2);
  757. onTest(1, "test");
  758. assert(val == 1);
  759. assert(text == "test");
  760. onTest(99, "te");
  761. assert(val == 99);
  762. assert(text == "te");
  763. }
  764. unittest
  765. {
  766. @safe void handler() {}
  767. Signal!() onTest;
  768. onTest.connect(&handler);
  769. bool thrown = false;
  770. try
  771. onTest.connect(&handler);
  772. catch(Throwable)
  773. thrown = true;
  774. assert(thrown);
  775. }
  776. unittest
  777. {
  778. @safe void handler() {};
  779. Signal!() onTest;
  780. onTest.connect(&handler);
  781. onTest.disconnect(&handler);
  782. onTest.connect(&handler);
  783. onTest();
  784. }
  785. unittest
  786. {
  787. bool called = false;
  788. @safe void handler() { called = true; };
  789. Signal!() onTest;
  790. onTest ~= &handler;
  791. onTest.disconnect(&handler);
  792. onTest ~= &handler;
  793. onTest();
  794. assert(called);
  795. }
  796. unittest
  797. {
  798. class handler
  799. {
  800. @safe void opCall(int i) {}
  801. }
  802. struct handler2
  803. {
  804. @safe void opCall(int i) {}
  805. }
  806. Signal!(int) onTest;
  807. onTest ~= new handler;
  808. auto h = onTest ~= new handler2;
  809. onTest(0);
  810. onTest.disconnect(h);
  811. }
  812. unittest
  813. {
  814. __gshared bool called = false;
  815. struct A
  816. {
  817. string payload;
  818. @trusted void opCall(float f, string s)
  819. {
  820. assert(payload == "payload");
  821. assert(f == 0.1234f);
  822. assert(s == "test call");
  823. called = true;
  824. }
  825. }
  826. A* a = new A();
  827. a.payload = "payload";
  828. Signal!(float, string) onTest;
  829. onTest.connect(a);
  830. onTest(0.1234f, "test call");
  831. assert(called);
  832. }
  833. unittest
  834. {
  835. __gshared bool called;
  836. struct A
  837. {
  838. string payload;
  839. @trusted void opCall(float f, string s)
  840. {
  841. assert(payload == "payload 2");
  842. called = true;
  843. }
  844. }
  845. A* a = new A();
  846. a.payload = "payload";
  847. Signal!(float, string) onTest;
  848. onTest.connect(a);
  849. A* b = new A();
  850. b.payload = "payload 2";
  851. onTest.connect(b);
  852. onTest.disconnect(a);
  853. onTest(0.1234f, "test call");
  854. assert(called);
  855. }
  856. unittest
  857. {
  858. struct A
  859. {
  860. @safe void opCall() {}
  861. }
  862. A* a = new A();
  863. Signal!() onTest;
  864. onTest.connect(a);
  865. bool thrown = false;
  866. try
  867. onTest.connect(a);
  868. catch(Throwable)
  869. thrown = true;
  870. assert(thrown);
  871. }
  872. unittest
  873. {
  874. struct A
  875. {
  876. @safe void opCall() {}
  877. }
  878. A* a = new A();
  879. Signal!() onTest;
  880. onTest.connect(a);
  881. onTest.disconnect(a);
  882. bool thrown = false;
  883. try
  884. onTest.disconnect(a);
  885. catch(Throwable)
  886. thrown = true;
  887. assert(thrown);
  888. }
  889. unittest
  890. {
  891. struct A
  892. {
  893. @safe void opCall() {}
  894. }
  895. A* a = new A();
  896. Signal!() onTest;
  897. bool thrown = false;
  898. try
  899. onTest.disconnect(a);
  900. catch(Throwable)
  901. thrown = true;
  902. assert(thrown);
  903. }
  904. unittest
  905. {
  906. bool secondCalled = false;
  907. @safe bool first(int i) {return false;}
  908. @safe void second(int i) {secondCalled = true;}
  909. Signal!(int) onTest;
  910. onTest ~= &first;
  911. onTest ~= &second;
  912. onTest(0);
  913. assert(!secondCalled);
  914. onTest.disconnect(&first);
  915. onTest ~= &first;
  916. onTest(0);
  917. assert(secondCalled);
  918. }
  919. unittest
  920. {
  921. @safe void second(int i) {}
  922. Signal!(int) onTest;
  923. auto t1 = onTest.getCallable(&second);
  924. auto t2 = onTest.getCallable(&second);
  925. auto t3 = onTest.getCallable(&second);
  926. assert(t1 == t2);
  927. assert(t2 == t3);
  928. }
  929. unittest
  930. {
  931. bool called = false;
  932. @safe void handler() { called = true; };
  933. Signal!() onTest;
  934. onTest ~= &handler;
  935. onTest();
  936. assert(called);
  937. called = false;
  938. onTest.enabled = false;
  939. onTest();
  940. assert(!called);
  941. onTest.enabled = true;
  942. onTest();
  943. assert(called);
  944. }
  945. unittest
  946. {
  947. @safe void handler() {};
  948. Signal!() onTest;
  949. assert(!onTest.isConnected(&handler));
  950. onTest ~= &handler;
  951. assert(onTest.isConnected(&handler));
  952. onTest();
  953. assert(onTest.isConnected(&handler));
  954. onTest.disconnect(&handler);
  955. assert(!onTest.isConnected(&handler));
  956. onTest();
  957. assert(!onTest.isConnected(&handler));
  958. }
  959. unittest
  960. {
  961. bool firstCalled, secondCalled, thirdCalled;
  962. @safe void handler1() {firstCalled = true;}
  963. @safe void handler2()
  964. {
  965. secondCalled = true;
  966. assert(firstCalled);
  967. assert(thirdCalled);
  968. }
  969. @safe void handler3()
  970. {
  971. thirdCalled = true;
  972. assert(firstCalled);
  973. assert(!secondCalled);
  974. }
  975. Signal!() onTest;
  976. onTest ~= &handler1;
  977. onTest ~= &handler2;
  978. auto h = onTest.connectAfter(&handler1, &handler3);
  979. assert(h == &handler3);
  980. onTest();
  981. assert(firstCalled && secondCalled && thirdCalled);
  982. }
  983. unittest
  984. {
  985. bool firstCalled, secondCalled;
  986. @safe void handler1() {firstCalled = true;}
  987. @safe void handler2()
  988. {
  989. secondCalled = true;
  990. assert(firstCalled);
  991. }
  992. Signal!() onTest;
  993. onTest ~= &handler2;
  994. onTest.connectFirst(&handler1);
  995. onTest();
  996. assert(firstCalled && secondCalled);
  997. }
  998. unittest
  999. {
  1000. bool firstCalled, secondCalled, thirdCalled;
  1001. @safe void handler1() {firstCalled = true;}
  1002. @safe void handler2()
  1003. {
  1004. secondCalled = true;
  1005. assert(firstCalled);
  1006. assert(!thirdCalled);
  1007. }
  1008. @safe void handler3()
  1009. {
  1010. thirdCalled = true;
  1011. assert(firstCalled);
  1012. assert(secondCalled);
  1013. }
  1014. Signal!() onTest;
  1015. onTest ~= &handler2;
  1016. auto h = onTest.connectAfter(&handler2, &handler3);
  1017. assert(h == &handler3);
  1018. auto h2 = onTest.connectBefore(&handler2, &handler1);
  1019. assert(h2 == &handler1);
  1020. onTest();
  1021. assert(firstCalled && secondCalled && thirdCalled);
  1022. firstCalled = secondCalled = thirdCalled = false;
  1023. onTest.disconnect(h);
  1024. onTest.disconnect(h2);
  1025. onTest.disconnect(&handler2);
  1026. onTest ~= &handler1;
  1027. onTest ~= &handler3;
  1028. onTest.connectBefore(&handler3, &handler2);
  1029. onTest();
  1030. assert(firstCalled && secondCalled && thirdCalled);
  1031. }
  1032. unittest
  1033. {
  1034. @safe void handler() {};
  1035. Signal!() onTest;
  1036. assert(onTest.calculateLength() == 0);
  1037. onTest.connect(&handler);
  1038. assert(onTest.calculateLength() == 1);
  1039. onTest.clear();
  1040. assert(onTest.calculateLength() == 0);
  1041. onTest();
  1042. }