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