PageRenderTime 425ms CodeModel.GetById 350ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 0ms

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