SirTony
8/23/2014 - 6:33 AM

A simple wrapper to handle both delegates and functions for the purposes of event callbacks, akin to .NET-style events.

A simple wrapper to handle both delegates and functions for the purposes of event callbacks, akin to .NET-style events.

/+
    A simple example showing usage of the
    EventHandler struct.
+/

import eventhandler;
import std.stdio;

class List( T )
{
    private alias EventHandler!( T ) AddedHandler;
    private AddedHandler onItemAdded;
    
    public ref AddedHandler ItemAdded() @property
    {
        return this.onItemAdded;
    }
    
    private T[] array;
    
    public T[] Items() @property
    {
        return this.array.dup;
    }
    
    public void Add( T item )
    {
        this.array ~= item;
        this.onItemAdded( item );
    }
}

void printNewItem( string item )
{
    "'%s' was added to the list.".writefln( item );
}

void main()
{
    auto list = new List!( string );
    list.ItemAdded += &printNewItem;
    
    list.Add( "foo" );
    // Output: 'foo' was added to the list.
}
module eventhandler;

/+
    EventHandler implementation.
+/

struct EventHandler( TArgs... )
{
    private import std.algorithm;
    
    public alias void delegate( TArgs ) DelegateType;
    public alias void function( TArgs ) FunctionType;
    
    private FunctionType[] functions;
    private DelegateType[] delegates;
    
    public void opAssign( T... )( T args )
    {
        throw new Exception( "EventHandler objects may not be assigned to directly, please use += or -= instead." );
    }
    
    public void opOpAssign( string op )( FunctionType fn ) if( op == "+" )
    {
        this.functions ~= fn;
    }
    
    public void opOpAssign( string op )( DelegateType dg ) if( op == "+" )
    {
        this.delegates ~= dg;
    }
    
    public void opOpAssign( string op )( FunctionType fn ) if( op == "-" )
    {
        if( !this.functions.canFind( fn ) )
            return;
        else
            this.functions = this.functions.remove!( x => x == fn );
    }
    
    public void opOpAssign( string op )( DelegateType dg ) if( op == "-" )
    {
        if( !this.delegates.canFind( dg ) )
            return;
        else
            this.delegates = this.delegates.remove!( x => x == dg );
    }
    
    public void opCall( TArgs args )
    {
        int len = max( this.delegates.length, this.functions.length );
        
        for( int i = 0; i < len; ++ i )
        {
            if( i < this.functions.length )
                this.functions[i]( args );
            
            if( i < this.delegates.length )
                this.delegates[i]( args );
        }
    }
}