internal static AwaitableStateConfiguration <TState, TTrigger> Permit <TState, TTrigger>( AwaitableStateConfiguration <TState, TTrigger> config, object predicate, TTrigger trigger, TState resultingState, object onTriggerAction, AwaitableTransitionFlag flags) { Contract.NotNull(trigger != null, nameof(trigger)); Contract.NotNull(resultingState != null, nameof(resultingState)); if ( AwaitableStateConfigurationHelper.FindTriggerRepresentation(trigger, config.CurrentStateRepresentation) != null) { ExceptionHelper.ThrowExclusiveOperation(); } var rep = AwaitableStateConfigurationHelper.CreateTriggerRepresentation(trigger, config.CurrentStateRepresentation); rep.NextStateRepresentationWrapper = AwaitableStateConfigurationHelper.FindOrCreateStateRepresentation(resultingState, config.Representations); rep.OnTriggerAction = onTriggerAction; rep.ConditionalTriggerPredicate = predicate; rep.AwaitableTransitionFlags |= flags; return(config); }
internal static async Task <bool> CanHandleTriggerAsync <TState, TTrigger>(TTrigger trigger, RawAwaitableStateMachineBase <TState, TTrigger> machine, bool exactMatch = false) { var res = await FindAndEvaluateTriggerRepresentationAsync(trigger, machine, false); if (res == null) { return(false); } if (!exactMatch) { return(true); } if (AwaitableStateConfigurationHelper.CheckFlag(res.AwaitableTransitionFlags, AwaitableTransitionFlag.DynamicState)) { if (await GetValidatedDynamicTransition <TState, TTrigger>(res) == null) { return(false); } } var currentType = res.OnTriggerAction.GetType(); return(AwaitableStateConfigurationHelper.CheckFlag(res.AwaitableTransitionFlags, AwaitableTransitionFlag.TriggerActionReturnsTask) ? currentType == typeof(Func <Task>) : currentType == typeof(Action)); }
internal static async Task <bool> CanHandleTriggerAsync <TState, TTrigger>(TTrigger trigger, RawAwaitableStateMachineBase <TState, TTrigger> machine, Type argumentType) { var res = await FindAndEvaluateTriggerRepresentationAsync(trigger, machine, false); if (res == null) { return(false); } if (AwaitableStateConfigurationHelper.CheckFlag(res.AwaitableTransitionFlags, AwaitableTransitionFlag.DynamicState)) { if (await GetValidatedDynamicTransition <TState, TTrigger>(res) == null) { return(false); } } var currentType = res.OnTriggerAction.GetType(); if (AwaitableStateConfigurationHelper.CheckFlag(res.AwaitableTransitionFlags, AwaitableTransitionFlag.TriggerActionReturnsTask)) { var targetType = typeof(Func <>).MakeGenericType(argumentType, typeof(Task)); return(currentType == targetType); } else { var targetType = typeof(Action <>).MakeGenericType(argumentType); return(currentType == targetType); } }
internal AwaitableStateConfiguration( Dictionary <TState, AwaitableStateRepresentation <TState, TTrigger> > representations, TState currentState) { Representations = representations; CurrentStateRepresentation = AwaitableStateConfigurationHelper.FindOrCreateStateRepresentation( currentState, representations); }
FindAndEvaluateTriggerRepresentationAsync <TState, TTrigger>(TTrigger trigger, RawAwaitableStateMachineBase <TState, TTrigger> machine, bool raiseInvalidTriggers = true) { var triggerRep = AwaitableStateConfigurationHelper.FindTriggerRepresentation(trigger, machine.CurrentStateRepresentation); if (triggerRep == null) { if (raiseInvalidTriggers) { machine.RaiseInvalidTrigger(trigger); } return(null); } if (AwaitableStateConfigurationHelper.CheckFlag(triggerRep.AwaitableTransitionFlags, AwaitableTransitionFlag.TriggerPredicateReturnsTask)) { var predicate = (Func <Task <bool> >)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!await predicate()) { if (raiseInvalidTriggers) { machine.RaiseInvalidTrigger(trigger); } return(null); } } } else { var predicate = (Func <bool>)triggerRep.ConditionalTriggerPredicate; if (predicate != null) { if (!predicate()) { if (raiseInvalidTriggers) { machine.RaiseInvalidTrigger(trigger); } return(null); } } } // Handle ignored trigger if (triggerRep.NextStateRepresentationWrapper == null) { return(null); } return(triggerRep); }
internal static async Task <DynamicState <TState>?> GetValidatedDynamicTransition <TState, TTrigger>( AwaitableTriggerRepresentation <TTrigger> triggerRep) { DynamicState <TState> dynamicState; if (AwaitableStateConfigurationHelper.CheckFlag(triggerRep.AwaitableTransitionFlags, AwaitableTransitionFlag.DynamicStateReturnsTask)) { dynamicState = await((Func <Task <DynamicState <TState> > >)triggerRep.NextStateRepresentationWrapper)(); } else { dynamicState = ((Func <DynamicState <TState> >)triggerRep.NextStateRepresentationWrapper)(); } return(dynamicState.CanTransition ? new DynamicState <TState>?(dynamicState) : null); }
internal static AwaitableStateConfiguration <TState, TTrigger> Ignore <TState, TTrigger>( AwaitableStateConfiguration <TState, TTrigger> config, object predicate, TTrigger trigger, AwaitableTransitionFlag flags) { Contract.NotNull(trigger != null, nameof(trigger)); if ( AwaitableStateConfigurationHelper.FindTriggerRepresentation(trigger, config.CurrentStateRepresentation) != null) { ExceptionHelper.ThrowExclusiveOperation(); } var rep = AwaitableStateConfigurationHelper.CreateTriggerRepresentation(trigger, config.CurrentStateRepresentation); rep.NextStateRepresentationWrapper = null; rep.ConditionalTriggerPredicate = predicate; rep.AwaitableTransitionFlags |= flags; return(config); }
internal static AwaitableStateConfiguration <TState, TTrigger> PermitDynamic <TState, TTrigger>( AwaitableStateConfiguration <TState, TTrigger> config, TTrigger trigger, object targetStateFunc, object onTriggerAction, AwaitableTransitionFlag flags) { Contract.NotNull(trigger != null, nameof(trigger)); Contract.NotNull(targetStateFunc != null, nameof(targetStateFunc)); if ( AwaitableStateConfigurationHelper.FindTriggerRepresentation(trigger, config.CurrentStateRepresentation) != null) { ExceptionHelper.ThrowExclusiveOperation(); } var rep = AwaitableStateConfigurationHelper.CreateTriggerRepresentation(trigger, config.CurrentStateRepresentation); rep.NextStateRepresentationWrapper = targetStateFunc; rep.OnTriggerAction = onTriggerAction; rep.ConditionalTriggerPredicate = null; rep.AwaitableTransitionFlags |= flags; return(config); }
internal static async Task FireCoreAsync <TState, TTrigger>(TTrigger trigger, RawAwaitableStateMachineBase <TState, TTrigger> machine, bool raiseInvalidStateOrTrigger = true) { var currentStateRepresentation = machine.CurrentStateRepresentation; var triggerRep = await AwaitableDiagnosticsHelper.FindAndEvaluateTriggerRepresentationAsync(trigger, machine, raiseInvalidStateOrTrigger); if (triggerRep == null) { return; } // Catch invalid paramters before execution. Action <Transition <TState, TTrigger> > triggerAction = null; Func <Transition <TState, TTrigger>, Task> triggerFunc = null; if (AwaitableStateConfigurationHelper.CheckFlag(triggerRep.AwaitableTransitionFlags, AwaitableTransitionFlag.TriggerActionReturnsTask)) { try { triggerFunc = (Func <Transition <TState, TTrigger>, Task>)triggerRep.OnTriggerAction; } catch (InvalidCastException) { if (raiseInvalidStateOrTrigger) { machine.RaiseInvalidTrigger(trigger); } return; } } else { try { triggerAction = (Action <Transition <TState, TTrigger> >)triggerRep.OnTriggerAction; } catch (InvalidCastException) { if (raiseInvalidStateOrTrigger) { machine.RaiseInvalidTrigger(trigger); } return; } } AwaitableStateRepresentation <TState, TTrigger> nextStateRep = null; if (AwaitableStateConfigurationHelper.CheckFlag(triggerRep.AwaitableTransitionFlags, AwaitableTransitionFlag.DynamicState)) { var dynamicState = await AwaitableDiagnosticsHelper.GetValidatedDynamicTransition <TState, TTrigger>(triggerRep); if (dynamicState == null) { return; } var state = dynamicState.Value.ResultingState; nextStateRep = AwaitableStateConfigurationHelper.FindStateRepresentation(state, machine.Representations); if (nextStateRep == null) { if (raiseInvalidStateOrTrigger) { machine.RaiseInvalidState(state); } return; } } else { nextStateRep = (AwaitableStateRepresentation <TState, TTrigger>)triggerRep.NextStateRepresentationWrapper; } var transition = new Transition <TState, TTrigger>(currentStateRepresentation.State, nextStateRep.State); machine.RaiseTransitionStarted(nextStateRep.State); // Current exit if ( AwaitableStateConfigurationHelper.CheckFlag( currentStateRepresentation.AwaitableTransitionFlags, AwaitableTransitionFlag.ExitReturnsTask)) { var exit = (Func <Transition <TState, TTrigger>, Task>)currentStateRepresentation.OnExitAction; if (exit != null) { await exit(transition); } } else { var exit = (Action <Transition <TState, TTrigger> >)currentStateRepresentation.OnExitAction; exit?.Invoke(transition); } // Trigger entry if (triggerAction != null) { triggerAction(transition); } else if (triggerFunc != null) { await triggerFunc(transition); } // Next entry if ( AwaitableStateConfigurationHelper.CheckFlag( nextStateRep.AwaitableTransitionFlags, AwaitableTransitionFlag.EntryReturnsTask)) { var entry = (Func <Transition <TState, TTrigger>, Task>)nextStateRep.OnEntryAction; if (entry != null) { await entry(transition); } } else { var entry = (Action <Transition <TState, TTrigger> >)nextStateRep.OnEntryAction; entry?.Invoke(transition); } var pastState = machine.CurrentState; machine.CurrentStateRepresentation = nextStateRep; machine.RaiseTransitionExecuted(pastState); }
internal static async Task MoveToStateCoreAsync <TState, TTrigger>(TState state, StateTransitionOption option, RawAwaitableStateMachineBase <TState, TTrigger> machine, bool raiseInvalidStates = true) { AwaitableStateRepresentation <TState, TTrigger> targetRep; if (machine.Representations.TryGetValue(state, out targetRep)) { var currentRep = machine.CurrentStateRepresentation; machine.RaiseTransitionStarted(targetRep.State); var transition = new Transition <TState, TTrigger>(currentRep.State, state); if ((option & StateTransitionOption.CurrentStateExitTransition) == StateTransitionOption.CurrentStateExitTransition) { if ( AwaitableStateConfigurationHelper.CheckFlag( currentRep.AwaitableTransitionFlags, AwaitableTransitionFlag.ExitReturnsTask)) { var action = currentRep.OnExitAction as Func <Transition <TState, TTrigger>, Task>; if (action != null) { await action(transition); } } else { var action = currentRep.OnExitAction as Action <Transition <TState, TTrigger> >; action?.Invoke(transition); } } if ((option & StateTransitionOption.NewStateEntryTransition) == StateTransitionOption.NewStateEntryTransition) { if (AwaitableStateConfigurationHelper.CheckFlag( targetRep.AwaitableTransitionFlags, AwaitableTransitionFlag.EntryReturnsTask)) { var action = targetRep.OnEntryAction as Func <Transition <TState, TTrigger>, Task>; if (action != null) { await action(transition); } } else { var action = targetRep.OnEntryAction as Action <Transition <TState, TTrigger> >; action?.Invoke(transition); } } var pastState = currentRep.State; machine.CurrentStateRepresentation = targetRep; machine.RaiseTransitionExecuted(pastState); } else { if (raiseInvalidStates) { machine.RaiseInvalidState(state); } } }