1 /*******************************************************************************
2  * Core module for state transion
3  * 
4  * Copyright: © 2019, SHOO
5  * License: [BSL-1.0](http://boost.org/LICENSE_1_0.txt).
6  * Author: SHOO
7  */
8 module cushion.core;
9 
10 
11 import std.traits, std.range, std.meta, std.container;
12 import cushion.handler;
13 import cushion._internal.misc;
14 
15 
16 private template isStraight(int start, Em...)
17 {
18 	static if (Em.length == 1)
19 	{
20 		enum isStraight = Em[0] == start;
21 	}
22 	else
23 	{
24 		enum isStraight = Em[0] == start && isStraight!(start+1, Em[1..$]);
25 	}
26 }
27 
28 
29 private template isStraightEnum(E)
30 	if (is(E == enum))
31 {
32 	enum isStraightEnum = (EnumMembers!(E)[0] == cast(E)0) &&isStraight!(EnumMembers!(E)[0], EnumMembers!E);
33 }
34 
35 
36 
37 /*******************************************************************************
38  * Judge StateTransitor's Event
39  */
40 template isEvent(Event)
41 {
42 	enum bool isEvent = isStraightEnum!Event;
43 }
44 
45 /*******************************************************************************
46  * Judge StateTransitor's State
47  */
48 template isState(State)
49 {
50 	enum bool isState = isStraightEnum!State;
51 }
52 
53 /*******************************************************************************
54  * Judge StateTransitor's ProcHandler
55  */
56 template isProcessHandler(Handler)
57 {
58 	static if (isHandler!Handler
59 	        && is(HandlerReturnType!Handler == void)
60 	        && is(HandlerParameters!Handler == AliasSeq!()))
61 	{
62 		enum bool isProcessHandler = true;
63 	}
64 	else
65 	{
66 		enum bool isProcessHandler = false;
67 	}
68 }
69 
70 /*******************************************************************************
71  * Judge StateTransitor's ExceptionHandler
72  */
73 template isExceptionHandler(Handler)
74 {
75 	static if (isHandler!Handler
76 	        && is(HandlerReturnType!Handler == void)
77 	        && ( is(HandlerParameters!Handler == AliasSeq!(Exception))
78 	          || is(HandlerParameters!Handler == AliasSeq!(Throwable))))
79 	{
80 		enum bool isExceptionHandler = true;
81 	}
82 	else
83 	{
84 		enum bool isExceptionHandler = false;
85 	}
86 }
87 
88 ///
89 @safe unittest
90 {
91 	static assert(isExceptionHandler!(void delegate(Exception)@safe[]));
92 }
93 
94 
95 /*******************************************************************************
96  * Judge StateTransitor's EventHandler
97  */
98 template isEventHandler(Handler, Event)
99 {
100 	static if (isHandler!Handler
101 	        && is(HandlerReturnType!Handler == void)
102 	        && is(HandlerParameters!Handler == AliasSeq!(Event)))
103 	{
104 		enum bool isEventHandler = true;
105 	}
106 	else
107 	{
108 		enum bool isEventHandler = false;
109 	}
110 }
111 
112 
113 /*******************************************************************************
114  * Judge StateTransitor's EventHandler
115  */
116 template isStateChangedHandler(Handler, State)
117 {
118 	static if (isHandler!Handler
119 	        && is(HandlerReturnType!Handler == void)
120 	        && is(HandlerParameters!Handler == AliasSeq!(State, State)))
121 	{
122 		enum bool isStateChangedHandler = true;
123 	}
124 	else
125 	{
126 		enum bool isStateChangedHandler = false;
127 	}
128 }
129 
130 ///
131 @safe unittest
132 {
133 	enum State {a, b, c}
134 	static assert(isStateChangedHandler!(void delegate(State,State), State));
135 }
136 
137 
138 
139 
140 private void insertBack(E)(ref SList!E list, E e)
141 {
142 	list.insertAfter(list[], e);
143 }
144 
145 private void insertBack(E)(ref E[] ary, E e)
146 {
147 	ary ~= e;
148 }
149 private void insert(E)(ref E[] ary, E e)
150 {
151 	ary ~= e;
152 }
153 private void removeFront(E)(ref E[] ary)
154 {
155 	ary = ary[1..$];
156 }
157 
158 private void removeFront(E)(ref Array!E ary)
159 {
160 	ary.moveAt(0);
161 	ary.removeBack();
162 }
163 
164 /*******************************************************************************
165  * Judge StateTransitor's EventContainer
166  */
167 template isEventContainer(Container)
168 {
169 	static if (__traits(compiles, {
170 		import std.array;
171 		Container list = void;
172 		auto e = list.front;
173 		list.insertBack(e);
174 		list.insert(e);
175 		list.removeFront();
176 		if (list.empty) {}
177 	}))
178 	{
179 		enum bool isEventContainer = true;
180 	}
181 	else
182 	{
183 		enum bool isEventContainer = false;
184 	}
185 }
186 
187 ///
188 @system unittest
189 {
190 	enum E {a, b, c}
191 	static assert(isEventContainer!(E[]));
192 	static assert(isEventContainer!(SList!E));
193 	static assert(isEventContainer!(DList!E));
194 	static assert(isEventContainer!(Array!E));
195 }
196 
197 
198 
199 private class EventCancelException: Exception
200 {
201 	this() { super(null, null, 0); }
202 }
203 
204 /*******************************************************************************
205  * 
206  */
207 void cancelEvent()
208 {
209 	throw new EventCancelException;
210 }
211 
212 
213 private class ForbiddenTransitionError: Error
214 {
215 	this(string msg = null, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line); }
216 }
217 
218 /***************************************************************************
219  * Get a default forbidden handler
220  */
221 void delegate() forbiddenHandler() @safe
222 {
223 	static struct Dummy
224 	{
225 		void forbidden()
226 		{
227 			throw new ForbiddenTransitionError;
228 		}
229 	}
230 	static Dummy dummy;
231 	return &dummy.forbidden;
232 }
233 
234 /***************************************************************************
235  * Get a default ignore handler
236  */
237 void delegate() ignoreHandler() @safe
238 {
239 	return null;
240 }
241 
242 /***************************************************************************
243  * Consume mode
244  */
245 enum ConsumeMode
246 {
247 	
248 	/***************************************************************************
249 	 * Events are consumed at the same time as addition.
250 	 * 
251 	 * Add an event with the put method, since the put method consumes events on
252 	 * the fly, we automatically call the consume method.
253 	 */
254 	combined,
255 	
256 	/***************************************************************************
257 	 * Events are consumed at separate timing from the of addition
258 	 * 
259 	 * Need to add an event with the put method and call the consume method for
260 	 * consumption.
261 	 */
262 	separate
263 }
264 
265 /*******************************************************************************
266  * StateTransitor
267  */
268 struct StateTransitor(
269 	StateType, EventType, StateType defaultStateParameter = StateType.init,
270 	ProcHandler         = void delegate()[],
271 	ExceptionHandler    = void delegate(Exception)[],
272 	EventHandler        = void delegate(EventType)[],
273 	StateChangedHandler = void delegate(StateType newSts, StateType oldSts)[],
274 	ConsumeMode consumeMode = ConsumeMode.combined,
275 	EventContainer = SList!EventType)
276 {
277 	static assert(isState!StateType);
278 	static assert(isEvent!EventType);
279 	static assert(isProcessHandler!ProcHandler);
280 	static assert(isExceptionHandler!ExceptionHandler);
281 	static assert(isEventHandler!(EventHandler, EventType));
282 	static assert(isStateChangedHandler!(StateChangedHandler, StateType));
283 	
284 	/***************************************************************************
285 	 * State type of this StateTransitor
286 	 */
287 	alias State = StateType;
288 	
289 	/***************************************************************************
290 	 * State type of this StateTransitor
291 	 */
292 	alias Event = EventType;
293 	
294 	/***************************************************************************
295 	 * Count of kind of state in this StateTransitor
296 	 */
297 	enum size_t stateCount = EnumMembers!(State).length;
298 	
299 	/***************************************************************************
300 	 * Count of kind of event in this StateTransitor(Not a count of unconsumed event)
301 	 */
302 	enum size_t eventCount = EnumMembers!(Event).length;
303 	
304 	/***************************************************************************
305 	 * Default state of this StateTransitor
306 	 */
307 	enum State defaultState = defaultStateParameter;
308 	
309 	/***************************************************************************
310 	 * Cell of table
311 	 */
312 	static struct Cell
313 	{
314 		/// next state
315 		State       nextState = defaultState;
316 		/// handler
317 		ProcHandler handler;
318 		/// Constructor
319 		pragma(inline) this(State s, ProcHandler h)
320 		{
321 			nextState = s;
322 			handler   = h;
323 		}
324 		/// ditto
325 		pragma(inline) this(Func)(State s, Func h)
326 			if (isHandlerAddable!(ProcHandler, Func))
327 		{
328 			nextState = s;
329 			cushion.handler.set(handler, h);
330 		}
331 	}
332 private:
333 	Cell[stateCount][eventCount] _table;
334 	State                        _currentState = defaultState;
335 	string                       _matrixName;
336 	string[stateCount]           _stateNames;
337 	string[eventCount]           _eventNames;
338 	ExceptionHandler             _exceptionHandler;
339 	EventHandler                 _eventHandler;
340 	StateChangedHandler          _stateChangedHandler;
341 	EventContainer               _events;
342 	
343 public:
344 	
345 	/***************************************************************************
346 	 * Constractor
347 	 */
348 	pragma(inline) this(Cell[stateCount][eventCount] tbl)
349 	{
350 		initialize(tbl);
351 	}
352 	
353 	/***************************************************************************
354 	 * Initialize of table
355 	 */
356 	pragma(inline) void initialize(Cell[stateCount][eventCount] tbl)
357 	{
358 		import std.algorithm;
359 		move(tbl, _table);
360 		cushion.handler.clear(_exceptionHandler);
361 		cushion.handler.clear(_stateChangedHandler);
362 		cushion.handler.clear(_eventHandler);
363 		_events.clear();
364 	}
365 	
366 	/***************************************************************************
367 	 * Get/Set matrix name
368 	 */
369 	void matrixName(string str) @safe @nogc nothrow pure @property
370 	{
371 		_matrixName = str;
372 	}
373 	
374 	/// ditto
375 	string matrixName() @safe @nogc nothrow pure const @property
376 	{
377 		return _matrixName;
378 	}
379 	
380 	/***************************************************************************
381 	 * Set/Get event names
382 	 */
383 	void setEventName(Event ev, string evname) @safe @nogc nothrow pure
384 	{
385 		assert(ev < _eventNames.length);
386 		_eventNames[ev] = evname;
387 	}
388 	
389 	/// ditto
390 	string getEventName(Event ev) @safe @nogc pure const
391 	{
392 		assert(ev < _eventNames.length);
393 		return _eventNames[ev];
394 	}
395 	
396 	/// ditto
397 	void eventNames(in string[eventCount] names) @safe @nogc nothrow pure @property
398 	{
399 		_eventNames[] = names[];
400 	}
401 	
402 	/// ditto
403 	const(string)[] eventNames() @safe @nogc nothrow pure const @property
404 	{
405 		return _eventNames;
406 	}
407 	
408 	
409 	/***************************************************************************
410 	 * Set/Get state names
411 	 */
412 	void setStateName(State st, string stname) @safe @nogc nothrow pure
413 	{
414 		assert(st < _stateNames.length);
415 		_stateNames[st] = stname;
416 	}
417 	
418 	/// ditto
419 	string getStateName(State st) @safe @nogc pure const
420 	{
421 		assert(st < _stateNames.length);
422 		return _stateNames[st];
423 	}
424 	
425 	/// ditto
426 	void stateNames(in string[stateCount] names) @safe @nogc nothrow pure @property
427 	{
428 		_stateNames[] = names[];
429 	}
430 	
431 	/// ditto
432 	const(string)[] stateNames() @safe nothrow pure const @property
433 	{
434 		return _stateNames;
435 	}
436 	
437 	
438 	/***************************************************************************
439 	 * Check current state
440 	 */
441 	State currentState() @safe @nogc nothrow pure const @property
442 	{
443 		return _currentState;
444 	}
445 	
446 	
447 	/***************************************************************************
448 	 * Change current state enforcely
449 	 */
450 	void enforceState(State sts) @system @nogc nothrow pure
451 	{
452 		_currentState = sts;
453 	}
454 	
455 	
456 	/***************************************************************************
457 	 * Set next state
458 	 * 
459 	 * If the state is `s` and event `e` is consumed, the next state will be `nextState`
460 	 */
461 	void setNextState(State s, Event e, State nextState)
462 	{
463 		_table[e][s].nextState = nextState;
464 	}
465 	
466 	/***************************************************************************
467 	 * Set handler
468 	 * 
469 	 * If the state is `s` and event `e` is consumed, the `handler` will be called.
470 	 * If other handler has already been set, the other handler is no longer used and replaced by `handler` instead.
471 	 */
472 	void setHandler(Func)(State s, Event e, Func handler)
473 		if (isHandlerAssignable!(ProcHandler, Func))
474 	{
475 		cushion.handler.set(_table[e][s].handler, handler);
476 	}
477 	
478 	/***************************************************************************
479 	 * Add handler
480 	 * 
481 	 * If the state is `s` and event `e` is consumed, the `handler` will be called.
482 	 * If other handler has already been set, `handler` will be added to the other handler and executed.
483 	 */
484 	void addHandler(Func)(State s, Event e, Func handler)
485 		if (isHandlerAddable!(ProcHandler, Func))
486 	{
487 		cushion.handler.add(_table[e][s].handler, handler);
488 	}
489 	
490 	
491 	/***************************************************************************
492 	 * Remove handler related `s` and `e`.
493 	 */
494 	void removeHandler(Func)(State s, Event e, Func handler)
495 		if (isHandlerAddable!(ProcHandler, Func))
496 	{
497 		cushion.handler.remove(_table[e][s].handler, handler);
498 	}
499 	
500 	/***************************************************************************
501 	 * Remove all handler related `s` and `e`.
502 	 */
503 	void clearHandler(State s, Event e)
504 	{
505 		cushion.handler.clear(_table[e][s].handler);
506 	}
507 	
508 	
509 	/***************************************************************************
510 	 * Set exception handler
511 	 * 
512 	 * If other handler has already been set, the other handler is no longer used and replaced by `handler` instead.
513 	 */
514 	void setExceptionHandler(Func)(Func handler)
515 		if (isHandlerAssignable!(ExceptionHandler, Func))
516 	{
517 		cushion.handler.set(_exceptionHandler, handler);
518 	}
519 	
520 	/***************************************************************************
521 	 * Add exception handler
522 	 * 
523 	 * If other handler has already been set, `handler` will be added to the other handler and executed.
524 	 */
525 	void addExceptionHandler(Func)(Func handler)
526 		if (isHandlerAddable!(ExceptionHandler, Func))
527 	{
528 		cushion.handler.add(_exceptionHandler, handler);
529 	}
530 	
531 	/***************************************************************************
532 	 * Remove exception handler.
533 	 */
534 	void removeExceptionHandler(Func)(Func handler)
535 		if (isHandlerAddable!(ExceptionHandler, Func))
536 	{
537 		cushion.handler.remove(_exceptionHandler, handler);
538 	}
539 	
540 	/***************************************************************************
541 	 * Remove all exception handler.
542 	 */
543 	void clearExceptionHandler()
544 	{
545 		cushion.handler.clear(_exceptionHandler);
546 	}
547 	
548 	
549 	/***********************************************************************
550 	 * Set event handler
551 	 * 
552 	 * If other handler has already been set, the other handler is no longer used and replaced by `handler` instead.
553 	 */
554 	void setEventHandler(Func)(Func handler)
555 		if (isHandlerAssignable!(EventHandler, Func))
556 	{
557 		cushion.handler.set(_eventHandler, handler);
558 	}
559 	
560 	/***********************************************************************
561 	 * Add event handler
562 	 * 
563 	 * If other handler has already been set, `handler` will be added to the other handler and executed.
564 	 */
565 	void addEventHandler(Func)(Func handler)
566 		if (isHandlerAddable!(EventHandler, Func))
567 	{
568 		cushion.handler.add(_eventHandler, handler);
569 	}
570 	
571 	/***********************************************************************
572 	 * Remove event handler.
573 	 */
574 	void removeEventHandler(Func)(Func handler)
575 		if (isHandlerAddable!(EventHandler, Func))
576 	{
577 		cushion.handler.remove(_eventHandler, handler);
578 	}
579 	
580 	/***********************************************************************
581 	 * Remove all event handler.
582 	 */
583 	void clearEventHandler()
584 	{
585 		cushion.handler.clear(_eventHandler);
586 	}
587 	
588 	
589 	/***************************************************************************
590 	 * Set state changed handler
591 	 * 
592 	 * If other handler has already been set, the other handler is no longer used and replaced by `handler` instead.
593 	 */
594 	void setStateChangedHandler(Func)(Func handler)
595 		if (isHandlerAssignable!(StateChangedHandler, Func))
596 	{
597 		cushion.handler.set(_stateChangedHandler, handler);
598 	}
599 	
600 	/***************************************************************************
601 	 * Add state changed handler
602 	 * 
603 	 * If other handler has already been set, `handler` will be added to the other handler and executed.
604 	 */
605 	void addStateChangedHandler(Func)(Func handler)
606 		if (isHandlerAddable!(StateChangedHandler, Func))
607 	{
608 		cushion.handler.add(_stateChangedHandler, handler);
609 	}
610 	
611 	/***************************************************************************
612 	 * Remove state changed handler.
613 	 */
614 	void removeStateChangedHandler(Func)(Func handler)
615 		if (isHandlerAddable!(StateChangedHandler, Func))
616 	{
617 		cushion.handler.remove(_stateChangedHandler, handler);
618 	}
619 	
620 	/***********************************************************************
621 	 * Remove all state changed handler.
622 	 */
623 	void clearStateChangedHandler()
624 	{
625 		cushion.handler.clear(_stateChangedHandler);
626 	}
627 	
628 	/***************************************************************************
629 	 * Add a event
630 	 */
631 	void put(Event e) @safe
632 	{
633 		if (!_events.empty)
634 		{
635 			_events.insertBack(e);
636 			return;
637 		}
638 		else
639 		{
640 			_events.insert(e);
641 		}
642 		while (consumeMode == ConsumeMode.combined && !_events.empty)
643 			consume();
644 	}
645 	
646 	/***************************************************************************
647 	 * Consume a event
648 	 */
649 	void consume() @safe
650 	{
651 		if (_events.empty)
652 			return;
653 		try
654 		{
655 			auto ev = _events.front;
656 			bool cancel;
657 			try
658 			{
659 				cushion.handler.call(_eventHandler, ev);
660 				cushion.handler.call(_table[ev][_currentState].handler);
661 			}
662 			catch (EventCancelException e)
663 			{
664 				cancel = true;
665 			}
666 			if (!cancel)
667 			{
668 				auto oldstate = _currentState;
669 				_currentState = _table[ev][_currentState].nextState;
670 				cushion.handler.call(_stateChangedHandler, oldstate, _currentState);
671 			}
672 		}
673 		catch (HandlerParameters!ExceptionHandler[0] e)
674 		{
675 			cushion.handler.call(_exceptionHandler, e);
676 		}
677 		// _eventsが空でなければ、必ずremoveFrontできなければならない。
678 		// できないならば、それはおかしい。
679 		() @trusted
680 		{
681 			assert(!_events.empty);
682 			try
683 			{
684 				_events.removeFront();
685 			}
686 			catch (Throwable e)
687 			{
688 				assert(0);
689 			}
690 		}();
691 	}
692 	
693 	/***************************************************************************
694 	 * Check for unconsumed events
695 	 */
696 	bool emptyEvents() const @property
697 	{
698 		return _events.empty;
699 	}
700 }
701 
702 /// ditto
703 template StateTransitor(alias Policy)
704 	if (__traits(hasMember, Policy, "State")
705 	 && __traits(hasMember, Policy, "Event"))
706 {
707 	alias State = Policy.State;
708 	alias Event = Policy.Event;
709 	alias StateTransitor = .StateTransitor!(
710 		State,
711 		Event,
712 		getMemberValue!(Policy, "defaultStateParameter", State.init),
713 		getMemberAlias!(Policy, "ProcHandler",           void delegate()[]),
714 		getMemberAlias!(Policy, "ExceptionHandler",      void delegate(Exception)[]),
715 		getMemberAlias!(Policy, "EventHandler",          void delegate(Event)[]),
716 		getMemberAlias!(Policy, "StateChangedHandler",   void delegate(State newSts, State oldSts)[]),
717 		getMemberValue!(Policy, "consumeMode",           ConsumeMode.combined),
718 		getMemberAlias!(Policy, "EventContainer",        SList!Event));
719 }
720 
721 ///
722 @safe unittest
723 {
724 	enum State { a, b }
725 	enum Event { e1, e2, e3 }
726 	
727 	alias Stm = StateTransitor!(State, Event);
728 	
729 	alias C = Stm.Cell;
730 	string msg;
731 	// STM
732 	auto sm = Stm([
733 		// Event     StateA                      StateB
734 		/* e1:   */ [C(State.b, {msg = "a-1";}), C(State.b, forbiddenHandler)],
735 		/* e2:   */ [C(State.a, ignoreHandler),  C(State.a, {msg = "b-2";})],
736 		/* e3:   */ [C(State.a, {msg = "a-3";}), C(State.a, forbiddenHandler)]
737 	]);
738 	static assert(isOutputRange!(typeof(sm), Event));
739 	
740 	assert(sm.currentState == State.a);
741 	std.range.put(sm, Event.e1);
742 	assert(sm.currentState == State.b);
743 	assert(msg == "a-1");
744 	sm.put(Event.e2);
745 	assert(sm.currentState == State.a);
746 	assert(msg == "b-2");
747 	sm.put(Event.e3);
748 	assert(sm.currentState == State.a);
749 	assert(msg == "a-3");
750 	sm.put(Event.e2);
751 	assert(sm.currentState == State.a);
752 	assert(msg == "a-3");
753 	sm.put(Event.e1);
754 	assert(sm.currentState == State.b);
755 	assert(msg == "a-1");
756 }
757 
758 ///
759 @safe unittest
760 {
761 	struct Policy
762 	{
763 		enum State { a, b }
764 		enum Event { e1, e2, e3 }
765 		enum consumeMode = ConsumeMode.separate;
766 	}
767 	alias Stm = StateTransitor!Policy;
768 	alias State = Policy.State;
769 	alias Event = Policy.Event;
770 	alias C = Stm.Cell;
771 	string[] msg;
772 	State[]  statesOnEvent;
773 	// STM
774 	auto sm = Stm([
775 		// Event     StateA                      StateB
776 		/* e1:   */ [C(State.b, {msg ~= "a-1";}), C(State.b, forbiddenHandler)],
777 		/* e2:   */ [C(State.a, ignoreHandler),   C(State.a, {msg ~= "b-2";})],
778 		/* e3:   */ [C(State.a, {msg ~= "a-3";}), C(State.a, forbiddenHandler)]
779 	]);
780 	sm.addEventHandler((Event e)
781 	{
782 		statesOnEvent ~= sm.currentState;
783 	});
784 	static assert(isOutputRange!(typeof(sm), Event));
785 	
786 	assert(sm.currentState == State.a);
787 	put(sm, [Event.e1, Event.e2, Event.e3, Event.e2, Event.e1]);
788 	assert(sm.currentState == State.a);
789 	
790 	while (!sm.emptyEvents)
791 		sm.consume();
792 	with (State)
793 		assert(statesOnEvent == [a, b, a, a, a]);
794 	assert(sm.currentState == State.b);
795 	assert(msg == ["a-1", "b-2", "a-3", "a-1"]);
796 }
797 
798 
799 @safe unittest
800 {
801 	enum S { sa, sb }
802 	enum E { ea, eb, ec }
803 	StateTransitor!(S, E) st;
804 	int x;
805 	void inc() { x++; }
806 	void inc2() { x++;x++; }
807 	void dec() { x++; }
808 	void ex(Exception e) {}
809 	void ex2(Exception e) {}
810 	void ev(E e) {}
811 	void ev2(E e) {}
812 	void sch(S a, S b) {}
813 	void sch2(S a, S b) {}
814 	st.setHandler(S.sa, E.ea, &inc);
815 	st.addHandler(S.sa, E.ea, &inc2);
816 	st.addHandler(S.sa, E.eb, &dec);
817 	st.setNextState(S.sa, E.eb, S.sb);
818 	st.removeHandler(S.sa, E.ea, &inc);
819 	st.clearHandler(S.sa, E.ea);
820 	
821 	st.setExceptionHandler(&ex);
822 	st.addExceptionHandler(&ex2);
823 	st.removeExceptionHandler(&ex);
824 	st.clearExceptionHandler();
825 	
826 	st.setEventHandler(&ev);
827 	st.addEventHandler(&ev2);
828 	st.removeEventHandler(&ev);
829 	st.clearEventHandler();
830 	
831 	st.setStateChangedHandler(&sch);
832 	st.addStateChangedHandler(&sch2);
833 	st.removeStateChangedHandler(&sch);
834 	st.clearStateChangedHandler();
835 }
836 
837 @safe unittest
838 {
839 	enum State { stop, play, pause }
840 	enum Event { onStart, onStop }
841 	auto stm = StateTransitor!(State, Event)();
842 	string txt;
843 	stm.addHandler(State.stop,  Event.onStart, (){ txt = "play"; });
844 	stm.addHandler(State.play,  Event.onStart, (){ txt = "pause"; });
845 	stm.addHandler(State.play,  Event.onStop,  (){ txt = "stop"; });
846 	stm.addHandler(State.pause, Event.onStart, (){ txt = "play"; });
847 	stm.addHandler(State.pause, Event.onStop,  (){ txt = "stop"; });
848 	stm.setNextState(State.stop,  Event.onStart, State.play);
849 	stm.setNextState(State.play,  Event.onStart, State.pause);
850 	stm.setNextState(State.play,  Event.onStop,  State.stop);
851 	stm.setNextState(State.pause, Event.onStart, State.play);
852 	stm.setNextState(State.pause, Event.onStop,  State.stop);
853 	
854 	assert(stm.currentState == State.stop);
855 	stm.put(Event.onStart);
856 	assert(txt == "play");
857 	assert(stm.currentState == State.play);
858 	stm.put(Event.onStop);
859 	assert(txt == "stop");
860 	assert(stm.currentState == State.stop);
861 	
862 }
863 
864 
865 
866 /*******************************************************************************
867  * Default Policy of StateTransitor
868  */
869 template CreateStateTransitorPolicy(
870 	State_, Event_, State_ defaultStateParameter_ = State_.init,
871 	ProcHandler_         = void delegate()[],
872 	ExceptionHandler_    = void delegate(Exception)[],
873 	EventHandler_        = void delegate(Event_)[],
874 	StateChangedHandler_ = void delegate(State_ newSts, State_ oldSts)[],
875 	ConsumeMode consumeMode_ = ConsumeMode.combined,
876 	EventContainer_ = SList!Event_)
877 {
878 	alias State                       = State_;
879 	alias Event                       = Event_;
880 	enum State_ defaultStateParameter = defaultStateParameter_;
881 	alias ProcHandler                 = ProcHandler_;
882 	alias ExceptionHandler            = ExceptionHandler_;
883 	alias EventHandler                = EventHandler_;
884 	alias StateChangedHandler         = StateChangedHandler_;
885 	enum ConsumeMode consumeMode      = consumeMode_;
886 	alias EventContainer              = EventContainer_;
887 }
888 
889 ///
890 @safe unittest
891 {
892 	enum MyState { a }
893 	enum MyEvent { a }
894 	alias ST1 = StateTransitor!(MyState, MyEvent);
895 	alias Policy2 = CreateStateTransitorPolicy!(MyState, MyEvent);
896 	alias ST2 = StateTransitor!Policy2;
897 	struct Policy3
898 	{
899 		alias State = MyState;
900 		alias Event = MyEvent;
901 	}
902 	alias ST3 = StateTransitor!Policy3;
903 	static assert(is(ST1 == ST2));
904 	static assert(is(ST1 == ST3));
905 }