1 module handler;
2 
3 import cushion;
4 import std.datetime.stopwatch;
5 
6 
7 ///
8 struct Handler(Args...)
9 {
10 private:
11 	void delegate(Args)[] _dgs;
12 public:
13 	///
14 	void connect(void delegate(Args) dg)
15 	{
16 		_dgs ~= dg;
17 	}
18 	
19 	///
20 	void disconnect(void delegate(Args) dg)
21 	{
22 		import std.algorithm: remove;
23 		_dgs = _dgs.remove!(a => a is dg);
24 	}
25 	
26 	///
27 	void emit(Args args)
28 	{
29 		foreach (dg; _dgs)
30 			dg(args);
31 	}
32 	
33 	///
34 	void clear()
35 	{
36 		_dgs = null;
37 	}
38 	
39 	///
40 	alias opCall = emit;
41 }
42 
43 static assert(isHandler!(Handler!()));
44 static assert(isHandler!(Handler!(int, int)));
45 static assert(is(HandlerParameters!(Handler!int)[0] == int));
46 static assert(is(HandlerReturnType!(Handler!int) == void));
47 
48 @safe unittest
49 {
50 	// Programs to be driven by STM
51 	string status = "stopped";
52 	StopWatch playTime;
53 	void startMusic() { playTime.start(); status = "playing"; }
54 	void stopMusic()  { playTime.stop();  status = "stopped"; }
55 	void resetMusic() { playTime.reset(); }
56 	
57 	// Create StateTransitor instance
58 	struct Policy
59 	{
60 		enum string name          = "MusicPlayer";
61 		enum string stateKey      = "#>";
62 		alias StateTransitor(S,E) = cushion.StateTransitor!(
63 			S, E, S.init, Handler!(), Handler!Exception, Handler!E, Handler!(S, S));
64 	}
65 	auto stm = createStm!(Policy, startMusic, stopMusic, resetMusic);
66 	// Initial state is "stop" that most left state.
67 	assert(stm.currentState == stm.State.stop);
68 	assert(stm.getStateName(stm.currentState) == "#>stop");
69 	assert(stm.getEventName(stm.Event.onStart) == "onStart");
70 	assert(status == "stopped");
71 	
72 	// onStart event / transit to the "#>play" state
73 	stm.put(stm.Event.onStart);
74 	assert(stm.currentState == stm.State.play);
75 	assert(playTime.running);
76 	() @trusted { import core.thread: Thread, msecs; Thread.sleep(10.msecs); }(); // progress in playing...
77 	assert(playTime.peek != 0.msecs);
78 	assert(status == "playing");
79 	
80 	// onStart event / transit to the "#>pause" state
81 	stm.put(stm.Event.onStart);
82 	assert(stm.currentState == stm.State.pause);
83 	assert(!playTime.running);
84 	assert(status == "stopped");
85 	
86 	// onStop event / transit to the "#>stop" state
87 	stm.put(stm.Event.onStop);
88 	assert(stm.currentState == stm.State.stop);
89 	assert(!playTime.running);
90 	() @trusted { import core.thread: Thread, msecs; Thread.sleep(10.msecs); }(); // progress in stopped...
91 	assert(playTime.peek == 0.msecs);
92 }