1 module tinyevent;
2 
3 /// Defines a regular event
4 alias Event(Args...) = void delegate(Args) @safe [];
5 /// Defines a cancelable event by returning false to cancel
6 alias Cancelable(Args...) = bool delegate(Args) @safe [];
7 
8 /// Calls all functions in a regular event
9 void emit(T : void delegate(Args), Args...)(T[] events, Args args) {
10 	foreach(fn; events)
11 		fn(args);
12 }
13 
14 /// Calls all functions in a cancelable event
15 bool emit(T : bool delegate(Args), Args...)(T[] events, Args args) {
16 	foreach(fn; events)
17 		if(!fn(args))
18 			return false;
19 	return true;
20 }
21 
22 /// Returns true if the type or variable is an Event!(...)
23 enum bool isEvent(T) = is(T : U[], U) && is(U : void delegate (Args), Args...);
24 /// Returns true if the type or variable is a Cancelable!(...)
25 enum bool isCancelable(T) = is(T : U[], U) && is(U : bool delegate (Args), Args...);
26 /// Returns true if the type or variable is an Event or Cancelable
27 enum bool isEmittable(T) = isEvent!T || isCancelable!T;
28 
29 ///
30 unittest {
31 	Event!string onStringChange;
32 	static assert (isEvent!(typeof(onStringChange)));
33 	static assert (!isCancelable!(typeof(onStringChange)));
34 	static assert (isEmittable!(typeof(onStringChange)));
35 	onStringChange ~= (s) { assert(s == "Foo"); };
36 	onStringChange.emit("Foo");
37 }
38 
39 ///
40 unittest {
41 	Cancelable!int onIntChange;
42 	static assert (!isEvent!(typeof(onIntChange)));
43 	static assert (isCancelable!(typeof(onIntChange)));
44 	static assert (isEmittable!(typeof(onIntChange)));
45 	int changed = 0;
46 	onIntChange ~= (i) { if(i > 5) return false; changed++; return true; };
47 	onIntChange ~= (i) { if(i > 4) return false; changed++; return true; };
48 	onIntChange ~= (i) { if(i > 3) return false; changed++; return true; };
49 	assert(onIntChange.emit(2));
50 	assert(changed == 3);
51 	
52 	changed = 0;
53 	assert(!onIntChange.emit(4));
54 	assert(changed == 2);
55 }
56 
57 // safety tests
58 @system unittest {
59 	void delegate(string, int, bool) @system [] eventSystem;
60 	eventSystem.emit("", 1, true);
61 }
62 
63 @safe unittest {
64 	void delegate(string, int, bool) @trusted [] eventTrusted;
65 	eventTrusted.emit("", 1, true);
66 	void delegate(string, int, bool) @safe [] eventSafe;
67 	eventSafe.emit("", 1, true);
68 }
69 
70 @safe nothrow unittest {
71 	void delegate(string, int, bool) @safe nothrow [] eventSafe;
72 	eventSafe.emit("", 1, true);
73 }
74 
75 unittest {
76 	string s;
77 	static assert (!isEvent!(typeof(s)));
78 	int i;
79 	static assert (!isEvent!(typeof(i)));
80 	void fn(int i) {
81 	}
82 	static assert (!isEvent!(typeof(fn)));
83 	static assert (isEvent!(typeof([&fn])));
84 	void function()[] fns;
85 	static assert (!isEvent!(typeof(fns)));
86 	void delegate()[] dels;
87 	static assert (isEvent!(typeof(dels)));
88 	Event!int e;
89 	static assert (isEvent!(typeof(e)));
90 	Cancelable!int c;
91 	static assert (isCancelable!(typeof(c)));
92 	static assert (isEmittable!(typeof(e)) && isEmittable!(typeof(c)));
93 	Event!() en;
94 	static assert (isEvent!(typeof(en)));
95 	Cancelable!() cn;
96 	static assert (isCancelable!(typeof(cn)));
97 	Event!(Event!int, int, string, Object) em;
98 	static assert (isEvent!(typeof(em)));
99 	Cancelable!(Object, string, void function(int, string)) cm;
100 	static assert (isCancelable!(typeof(cm)));
101 }