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 }