// WARNING: This is an internal implementation header, which must be included from a specific location/namespace // That is the reason that this header does not contain a #pragma once, nor namespace guards // Helper struct representing a transition event to a new FSM state struct TransitionEvent { Task<> newTask; StateId newStateId; }; // Base class for defining links between states class LinkBase { public: virtual ~LinkBase() = default; virtual std::optional EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const = 0; }; // Type-safe link handle class LinkHandle { bool IsOnCompleteLink() const { return m_linkType == eType::OnComplete; } bool HasCondition() const { return m_isConditionalLink; } protected: // Link-type enum enum class eType { Normal, OnComplete, }; // Friends template friend class StateHandle; friend class NAMESPACE_SQUID::TaskFSM; // Constructors (friend-only) LinkHandle() = delete; LinkHandle(std::shared_ptr in_link, eType in_linkType, bool in_isConditional) : m_link(std::move(in_link)) , m_linkType(in_linkType) , m_isConditionalLink(in_isConditional) { } std::optional EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const { return m_link->EvaluateLink(in_onTransitionFn); } private: std::shared_ptr m_link; // The underlying link eType m_linkType; // Whether the link is normal or OnComplete bool m_isConditionalLink; // Whether the link has an associated condition predicate }; // Internal FSM state object template struct State { State(tStateConstructorFn in_stateCtorFn, StateId in_stateId, std::string in_debugName) : stateCtorFn(in_stateCtorFn) , stateId(in_stateId) , debugName(in_debugName) { } tStateConstructorFn stateCtorFn; StateId stateId; std::string debugName; }; // Internal FSM state object (exit state specialization) template<> struct State { State(StateId in_stateId, std::string in_debugName) : stateId(in_stateId) , debugName(in_debugName) { } StateId stateId; std::string debugName; }; // Internal link definition object template class Link : public LinkBase { public: Link(std::shared_ptr> in_targetState, tPredicateFn in_predicate) : m_targetState(std::move(in_targetState)) , m_predicate(in_predicate) { } private: virtual std::optional EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final { std::optional result; if(std::optional payload = m_predicate()) { if(in_onTransitionFn) { in_onTransitionFn(); } result = TransitionEvent{ m_targetState->stateCtorFn(payload.value()), m_targetState->stateId }; } return result; } std::shared_ptr> m_targetState; tPredicateFn m_predicate; }; // Internal link definition object (no-payload specialization) template class Link : public LinkBase { public: Link(std::shared_ptr> in_targetState, tPredicateFn in_predicate) : m_targetState(std::move(in_targetState)) , m_predicate(in_predicate) { } private: virtual std::optional EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final { std::optional result; if(m_predicate()) { if(in_onTransitionFn) { in_onTransitionFn(); } result = TransitionEvent{ m_targetState->stateCtorFn(), m_targetState->stateId }; } return result; } std::shared_ptr> m_targetState; tPredicateFn m_predicate; }; // Internal link definition object (exit-state specialization) template class Link : public LinkBase { public: Link(std::shared_ptr> in_targetState, tPredicateFn in_predicate) : m_targetState(std::move(in_targetState)) , m_predicate(in_predicate) { } private: virtual std::optional EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final { std::optional result; if(m_predicate()) { if(in_onTransitionFn) { in_onTransitionFn(); } result = TransitionEvent{ Task<>(), m_targetState->stateId }; } return result; } std::shared_ptr> m_targetState; tPredicateFn m_predicate; }; // Specialized type traits that deduce the first argument type of an arbitrary callable type template static tArg get_first_arg_type(std::function f); // Return type is first argument type template static void get_first_arg_type(std::function f); // Return type is void (function has no arguments) template struct function_traits : public function_traits // Generic callable objects (use operator()) { }; template // Function struct function_traits { using tFunction = std::function; using tArg = decltype(get_first_arg_type(tFunction())); }; template // Function ptr struct function_traits { using tFunction = std::function; using tArg = decltype(get_first_arg_type(tFunction())); }; template // Member function ptr (const) struct function_traits { using tFunction = std::function; using tArg = decltype(get_first_arg_type(tFunction())); }; template // Member function ptr struct function_traits { using tFunction = std::function; using tArg = decltype(get_first_arg_type(tFunction())); };