internal async Task MoveToStateInternal(TState state, StateTransitionOption option) { var currentRep = CurrentStateRepresentation; AwaitableStateRepresentation <TState, TTrigger> rep; if (configDictionary.TryGetValue(state, out rep)) { if ((option & StateTransitionOption.CurrentStateExitTransition) == StateTransitionOption.CurrentStateExitTransition) { if (CheckFlag(currentRep.TransitionFlags, AwaitableStateTransitionFlag.ExitReturnsTask)) { var action = CurrentStateRepresentation.OnExitAction as Func <Task>; if (action != null) { await action(); } } else { var action = CurrentStateRepresentation.OnExitAction as Action; if (action != null) { action(); } } } if ((option & StateTransitionOption.NewStateEntryTransition) == StateTransitionOption.NewStateEntryTransition) { if (CheckFlag(rep.TransitionFlags, AwaitableStateTransitionFlag.EntryReturnsTask)) { var action = rep.OnEntryAction as Func <Task>; if (action != null) { await action(); } } else { var action = rep.OnEntryAction as Action; if (action != null) { action(); } } } CurrentStateRepresentation = rep; } else { throw new InvalidOperationException("Invalid state: " + state.ToString()); } }
internal AwaitableStateConfigurationHelper(Dictionary <TState, AwaitableStateRepresentation <TState, TTrigger> > config, TState currentState) { Contract.Requires(config != null); Contract.Requires(currentState != null); Contract.Ensures(currentStateRepresentation != null); this.config = config; currentStateRepresentation = FindOrCreateStateRepresentation(currentState, config); }
protected RawAwaitableStateMachineBase(TState initialState, AwaitableConfiguration <TState, TTrigger> awaitableConfiguration) { CurrentStateRepresentation = awaitableConfiguration.GetInitialStateRepresentation(initialState); if (CurrentStateRepresentation == null) { ExceptionHelper.ThrowInvalidState(initialState); } Representations = awaitableConfiguration.Representations; m_diagnostics = new RawAwaitableStateMachineDiagnostics <TState, TTrigger>(this); }
internal AwaitableStateMachine(TState initialState, AwaitableStateMachineConfiguration <TState, TTrigger> configuration) { Contract.Requires(configuration != null); Contract.Requires(initialState != null); CurrentStateRepresentation = configuration.GetInitialStateRepresentation(initialState); if (CurrentStateRepresentation == null) { throw new InvalidOperationException("StateMachine has an unreachable state"); } configDictionary = configuration.Config; }
internal AwaitableStateMachine(TState initialState, AwaitableStateMachineConfiguration <TState, TTrigger> configuration) { Contract.Requires(configuration != null); Contract.Requires(initialState != null); currentStateRepresentation = configuration.GetStateRepresentation(initialState); if (currentStateRepresentation == null) { throw new InvalidOperationException("StateMachine has no states"); } IsEnabled = true; }
internal static AwaitableStateRepresentation <TState, TTrigger> FindOrCreateStateRepresentation(TState state, Dictionary <TState, AwaitableStateRepresentation <TState, TTrigger> > config) { Contract.Requires(state != null); Contract.Requires(config != null); Contract.Ensures(Contract.Result <AwaitableStateRepresentation <TState, TTrigger> >() != null); AwaitableStateRepresentation <TState, TTrigger> rep; if (config.TryGetValue(state, out rep)) { if (rep != null) { return(rep); } } rep = new AwaitableStateRepresentation <TState, TTrigger>(state); config[state] = rep; return(rep); }
internal static AwaitableTriggerRepresentation <TTrigger, TState> FindTriggerRepresentation(TTrigger trigger, AwaitableStateRepresentation <TState, TTrigger> stateRepresentation) { return(stateRepresentation.Triggers.Find(x => x.Trigger.Equals(trigger))); }
internal static AwaitableTriggerRepresentation <TTrigger, TState> FindOrCreateTriggerConfig(TTrigger trigger, AwaitableStateRepresentation <TState, TTrigger> stateRepresentation) { Contract.Requires(stateRepresentation != null); Contract.Requires(trigger != null); Contract.Ensures(Contract.Result <AwaitableTriggerRepresentation <TTrigger, TState> >() != null); var rep = FindTriggerRepresentation(trigger, stateRepresentation); if (rep != null) { return(rep); } rep = new AwaitableTriggerRepresentation <TTrigger, TState>(trigger); stateRepresentation.Triggers.Add(rep); return(rep); }
internal async Task FireInternalAsync(TTrigger trigger) { var triggerRep = AwaitableStateConfigurationHelper <TState, TTrigger> .FindTriggerRepresentation(trigger, CurrentStateRepresentation); if (triggerRep == null) { HandleInvalidTrigger(trigger); return; } if (CheckFlag(triggerRep.TransitionFlags, AwaitableStateTransitionFlag.TriggerPredicateReturnsTask)) { var predicate = (Func <Task <bool> >)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!await predicate()) { HandleInvalidTrigger(trigger); return; } } } else { var predicate = (Func <bool>)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!predicate()) { HandleInvalidTrigger(trigger); return; } } } // Handle ignored trigger if (triggerRep.NextStateRepresentation == null) { return; } // Catch invalid paramters before execution. Action triggerAction = null; Func <Task> triggerFunc = null; if (CheckFlag(triggerRep.TransitionFlags, AwaitableStateTransitionFlag.TriggerActionReturnsTask)) { try { triggerFunc = (Func <Task>)triggerRep.OnTriggerAction; } catch (InvalidCastException) { InvalidTriggerParameterException <TTrigger> .Throw(trigger); return; } } else { try { triggerAction = (Action)triggerRep.OnTriggerAction; } catch (InvalidCastException) { InvalidTriggerParameterException <TTrigger> .Throw(trigger); return; } } // Current exit if (CheckFlag(CurrentStateRepresentation.TransitionFlags, AwaitableStateTransitionFlag.ExitReturnsTask)) { var exit = (Func <Task>)CurrentStateRepresentation.OnExitAction; if (exit != null) { await exit(); } } else { var exit = (Action)CurrentStateRepresentation.OnExitAction; if (exit != null) { exit(); } } // Trigger entry if (triggerAction != null) { triggerAction(); } else if (triggerFunc != null) { await triggerFunc(); } // Next state entry var nextStateRep = triggerRep.NextStateRepresentation; if (CheckFlag(nextStateRep.TransitionFlags, AwaitableStateTransitionFlag.EntryReturnsTask)) { var entry = (Func <Task>)nextStateRep.OnEntryAction; if (entry != null) { await entry(); } } else { var entry = (Action)nextStateRep.OnEntryAction; if (entry != null) { entry(); } } // Set states var previousState = CurrentStateRepresentation.State; CurrentStateRepresentation = nextStateRep; // Raise event var sc = StateChanged; if (sc != null) { sc.Invoke(previousState, CurrentStateRepresentation.State); } }
public async Task FireAsync <TArgument>(ParameterizedTrigger <TTrigger, TArgument> parameterizedTrigger, TArgument argument) { if (isRunning) { throw new InvalidOperationException("State cannot be changed while in transition"); } if (IsEnabled) { isRunning = true; var trigger = parameterizedTrigger.Trigger; var triggerRep = AwaitableStateConfigurationHelper <TState, TTrigger> .FindTriggerRepresentation(trigger, currentStateRepresentation); if (triggerRep == null) { HandleInvalidTrigger(trigger); return; } if (CheckFlag(triggerRep.TransitionFlags, AwaitableStateTransitionFlag.TriggerPredicateReturnsTask)) { var predicate = (Func <Task <bool> >)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!await predicate()) { HandleInvalidTrigger(trigger); return; } } } else { var predicate = (Func <bool>)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!predicate()) { HandleInvalidTrigger(trigger); return; } } } // Handle ignored trigger if (triggerRep.NextStateRepresentation == null) { return; } // Catch invalid paramters before execution. Action <TArgument> triggerAction = null; Func <TArgument, Task> triggerFunc = null; if (CheckFlag(triggerRep.TransitionFlags, AwaitableStateTransitionFlag.TriggerActionReturnsTask)) { try { triggerFunc = (Func <TArgument, Task>)triggerRep.OnTriggerAction; } catch (InvalidCastException) { InvalidTriggerParameterException <TTrigger> .Throw(trigger); return; } } else { try { triggerAction = (Action <TArgument>)triggerRep.OnTriggerAction; } catch (InvalidCastException) { InvalidTriggerParameterException <TTrigger> .Throw(trigger); return; } } // Current exit if (CheckFlag(currentStateRepresentation.TransitionFlags, AwaitableStateTransitionFlag.ExitReturnsTask)) { var exit = (Func <Task>)currentStateRepresentation.OnExitAction; if (exit != null) { await exit(); } } else { var exit = (Action)currentStateRepresentation.OnExitAction; if (exit != null) { exit(); } } // Trigger entry if (triggerAction != null) { triggerAction(argument); } else if (triggerFunc != null) { await triggerFunc(argument); } // Next state entry var nextStateRep = triggerRep.NextStateRepresentation; if (CheckFlag(nextStateRep.TransitionFlags, AwaitableStateTransitionFlag.EntryReturnsTask)) { var entry = (Func <Task>)nextStateRep.OnEntryAction; if (entry != null) { await entry(); } } else { var entry = (Action)nextStateRep.OnEntryAction; if (entry != null) { entry(); } } // Set states var previousState = currentStateRepresentation.State; currentStateRepresentation = nextStateRep; // Raise event var sc = StateChanged; if (sc != null) { sc(previousState, currentStateRepresentation.State); } isRunning = false; } }