Documentation
¶
Index ¶
- func AddCustomStateReaction[E any, C any, PE EventCst[E]](from StateSetupProxy[C], reaction Reaction[E, PE])
- func AddDefer[E any, C any, PE EventCst[E]](state StateSetupProxy[C])
- func AddDiscard[E any, C any, PE EventCst[E]](state StateSetupProxy[C])
- func AddInStateReaction[E any, C any, PE EventCst[E]](state StateSetupProxy[C], action Action[E, PE])
- func AddSimpleStateTransition[E any, S any, C any, PE EventCst[E], PS StateCst[S, C]](from StateSetupProxy[C], action Action[E, PE])
- func GeneticStateSelector[S any, C any, PS StateCst[S, C]](state State[C]) bool
- func GetAncestor[S any, C any, PS StateCst[S, C]](state StateProxy[C]) *S
- func SetStartingState[S any, C any, PS StateCst[S, C]](state StateSetupProxy[C])
- type Action
- type AsyncStateMachine
- func (sm *AsyncStateMachine[C]) AddState(state State[C]) StateId
- func (sm *AsyncStateMachine[C]) AddSubState(state State[C], parentId StateId) StateId
- func (sm *AsyncStateMachine[C]) Close()
- func (sm *AsyncStateMachine[C]) DispatchEvent(event Event)
- func (sm *AsyncStateMachine[C]) GenerateUml(w io.Writer, umlSyntax UmlSyntax, diagramType UmlDiagramType)
- func (sm *AsyncStateMachine[C]) Initialize(initStateId StateId)
- func (sm *AsyncStateMachine[C]) SetDebugLogger(logger func(msg string, keysAndValues ...interface{}))
- type BaseAction
- type EntryAction
- type Event
- type EventCst
- type EventDefault
- type EventReaction
- type ExitAction
- type Reaction
- type ReactionResult
- type ResultType
- type State
- type StateCst
- type StateDefault
- type StateId
- type StateMachine
- func (sm *StateMachine[C]) AddState(state State[C]) StateId
- func (sm *StateMachine[C]) AddSubState(state State[C], parentId StateId) StateId
- func (sm *StateMachine[C]) DispatchEvent(event Event)
- func (sm *StateMachine[C]) GenerateUml(w io.Writer, umlSyntax UmlSyntax, diagramType UmlDiagramType)
- func (sm *StateMachine[C]) Initialize(initStateId StateId)
- func (sm *StateMachine[C]) SetDebugLogger(logger func(msg string, keysAndValues ...interface{}))
- type StateProxy
- type StateSetupProxy
- type UmlDiagramType
- type UmlDocReaction
- type UmlSyntax
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddCustomStateReaction ¶
func AddCustomStateReaction[E any, C any, PE EventCst[E]](from StateSetupProxy[C], reaction Reaction[E, PE])
Add a custom reaction `E` is the event type `C` is the user context (deducted) `PE` is a pointer to E (deducted) `from` is the proxy of the current state `reaction` is the custom reaction function
func AddDefer ¶
func AddDefer[E any, C any, PE EventCst[E]](state StateSetupProxy[C])
Add a defer event reaction `E` is the event type `C` is the user context (deducted) `PE` is a pointer to E (deducted) `state` is the proxy of the current state
func AddDiscard ¶
func AddDiscard[E any, C any, PE EventCst[E]](state StateSetupProxy[C])
Add a discard event reaction `E` is the event type `C` is the user context (deducted) `PE` is a pointer to E (deducted) `state` is the proxy of the current state
func AddInStateReaction ¶
func AddInStateReaction[E any, C any, PE EventCst[E]](state StateSetupProxy[C], action Action[E, PE])
Add an in-state reaction `E` is the event type `C` is the user context (deducted) `PE` is a pointer to E (deducted) `state` is the proxy of the current state `action` is the action function
func AddSimpleStateTransition ¶
func AddSimpleStateTransition[E any, S any, C any, PE EventCst[E], PS StateCst[S, C]](from StateSetupProxy[C], action Action[E, PE])
Add a simple state transition `E` is the event type `S` is the actual user state that we are going to `C` is the user context (deducted) `PE` is a pointer to E (deducted) `PS` is a pointer to `S` (deducted) `from` is the proxy of the current state `action` is the action associated with the transition (optional)
func GeneticStateSelector ¶
Returns true if the state is of type `*S` This is used to find a state by Type `S` is the actual user state `C` is the user context (deducted) `PS` is pointer to S (deducted)
func GetAncestor ¶
func GetAncestor[S any, C any, PS StateCst[S, C]](state StateProxy[C]) *S
func SetStartingState ¶
func SetStartingState[S any, C any, PS StateCst[S, C]](state StateSetupProxy[C])
Set a starting state using a State Type as a key `S` is the actual user state `C` is the user context (deducted) `PS` is a pointer to `S` (deducted) `proxy` is the proxy to the internal state in the machine
Types ¶
type Action ¶
Action Type function that takes the a pointer to Event as argument `E` the event type `PE` is deducted (Pointer to E) `event` the event that triggered this action
type AsyncStateMachine ¶
type AsyncStateMachine[C any] struct { // contains filtered or unexported fields }
Example ¶
This Example Creates an Async State Machine. Please refer to [ExampleStateMachine1] for full example, [ExampleStateMachine1], [ExampleStateMachine2]
[ExampleStateMachine]: https://pkg.go.dev/github.com/hhassoubi/go-statechart#example-StateMachine [ExampleStateMachine1]: /github.com/hhassoubi/go-statechart#example-StateMachine [ExampleStateMachine2]: go-statechart#example-StateMachine
// Refer to [https://github.com/hhassoubi/go-statechart/blob/master/async_state_machine.go] // Create State Machine context := MyContext{} sm := statechart.MakeAsyncStateMachine(&context) idleState := sm.AddState(&Idle{}) activeState := sm.AddState(&Active{}) sm.AddSubState(&Stopped{}, activeState) sm.AddSubState(&Running{}, activeState) sm.Initialize(idleState) // example event dispatch sm.DispatchEvent(&ActivateEv{}) // go for Idle to Active to Stopped sm.DispatchEvent(&StartStopEv{}) // go from Stopped to Running sm.DispatchEvent(&ResetEv{}) // go from Running to Active to Stopped sm.DispatchEvent(&DeactivateEv{}) // go from Stopped to Idle sm.Close() // this will wait
Output: Reset Counter Start Counter Stop Counter Reset Counter
func MakeAsyncStateMachine ¶
func MakeAsyncStateMachine[C any](userContext_ *C) AsyncStateMachine[C]
Creates an async state machine with a user context
func (*AsyncStateMachine[C]) AddState ¶
func (sm *AsyncStateMachine[C]) AddState(state State[C]) StateId
Adds a new State to the State Machine `state` the new state object to add returns the new stateId
func (*AsyncStateMachine[C]) AddSubState ¶
func (sm *AsyncStateMachine[C]) AddSubState(state State[C], parentId StateId) StateId
Adds a Sub-State to the State Machine `state` the new state object to add `parentId` the parent (super state) ID
func (*AsyncStateMachine[C]) Close ¶
func (sm *AsyncStateMachine[C]) Close()
Closes the async channel
func (*AsyncStateMachine[C]) DispatchEvent ¶
func (sm *AsyncStateMachine[C]) DispatchEvent(event Event)
Dispatches an events to the state machine `event` The Event to dispatch No error will occur if the Event is unknown to the state machine
func (*AsyncStateMachine[C]) GenerateUml ¶ added in v0.6.0
func (sm *AsyncStateMachine[C]) GenerateUml(w io.Writer, umlSyntax UmlSyntax, diagramType UmlDiagramType)
Generates the UML diagram for the state machine, using `w` the io stream writer `umlSyntax` the generator syntax only only support PlantUML syntax for now [https://plantuml.com/state-diagram] `diagramType` the type of diagram to use for the generation
func (*AsyncStateMachine[C]) Initialize ¶
func (sm *AsyncStateMachine[C]) Initialize(initStateId StateId)
Initializes the state machine `initStateId` the initial starting state
func (*AsyncStateMachine[C]) SetDebugLogger ¶
func (sm *AsyncStateMachine[C]) SetDebugLogger(logger func(msg string, keysAndValues ...interface{}))
Sets the Debug Trace Logger for the state machine
type BaseAction ¶
type BaseAction func(event Event)
the abstract Action `event` the event that triggered this action
func ToBaseAction ¶
func ToBaseAction[E any, PE EventCst[E]](action Action[E, PE]) BaseAction
A function that convert an Action to a BaseAction. the new generated function will perform a safe down cast `action` the concrete action returns the abstract action
type Event ¶
type Event interface {
// contains filtered or unexported methods
}
The Event interface This is need needed to avoid casting interface{} to concrete Event
type EventCst ¶
Event Type Parameter Constraint. This is a trick to force event to be passed by pointer `E` is the concrete event
type EventDefault ¶
type EventDefault struct { }
type EventReaction ¶
type EventReaction struct {
// contains filtered or unexported fields
}
This is used to link an event to a custom reaction
func MakeEventReaction ¶
func MakeEventReaction[T any, PT EventCst[T]](reaction Reaction[T, PT], doc ...UmlDocReaction) EventReaction
makes an EventReaction from a custom reaction
type Reaction ¶
type Reaction[T any, PT EventCst[T]] func(PT) ReactionResult
Custom reaction function type.
type ReactionResult ¶
type ReactionResult struct {
// contains filtered or unexported fields
}
encapsulate the result for a reaction
func Transit ¶
func Transit[S any, C any, PS StateCst[S, C]](from StateProxy[C]) ReactionResult
func TransitWithAction ¶
func TransitWithAction[S any, C any, E any, PS StateCst[S, C], PE EventCst[E]](from StateProxy[C], action Action[E, PE]) ReactionResult
type ResultType ¶
type ResultType int16
const ( // Forwards the event to the parent state FORWARD ResultType = iota // Discards the event DISCARD // Transit to a new state TRANSIT // defer the event to be posted after state change DEFER )
type State ¶
type State[C any] interface { Setup(proxy StateSetupProxy[C]) (EntryAction, ExitAction) // contains filtered or unexported methods }
The State[C] Interface where `C` is the user context
type StateCst ¶
State Type Parameter Constraint. `S` is the actual user state `C` is the user context
type StateDefault ¶
type StateDefault[C any] struct { // contains filtered or unexported fields }
Default implementation of State[C], This could be used to simplify the API in the concrete state
func (*StateDefault[C]) GetAncestor ¶
func (s *StateDefault[C]) GetAncestor(state StateId) State[C]
func (*StateDefault[C]) GetContext ¶
func (s *StateDefault[C]) GetContext() *C
func (*StateDefault[C]) Init ¶
func (s *StateDefault[C]) Init(proxy StateProxy[C])
Initializing the state.
func (*StateDefault[C]) Proxy ¶
func (s *StateDefault[C]) Proxy() StateProxy[C]
type StateId ¶
type StateId int
The State identifier generated by the state machine when calling AddState
var INVALID_STATE_ID StateId = -1
func FindStateId ¶
func FindStateId[S any, C any, PS StateCst[S, C]](proxy StateProxy[C]) StateId
Finds the state id of the state that matches the Concrete State Type `S` is the actual user state `C` is the user context (deducted) `PS` is a pointer to `S` (deducted) `proxy` is the proxy to the internal state in the machine
type StateMachine ¶
type StateMachine[C any] struct { // contains filtered or unexported fields }
Example ¶
// MIT License: https://github.com/hhassoubi/go-statechart/blob/master/LICENSE // Copyright (c) 2023 Hicham Hassoubi package main import ( "fmt" "github.com/hhassoubi/go-statechart" ) // // Events type StartStopEv struct { statechart.EventDefault } type ActivateEv struct { statechart.EventDefault } type DeactivateEv struct { statechart.EventDefault } type ResetEv struct { statechart.EventDefault } type MyContext struct { } func (*MyContext) StartCounter() { // Start Counter Code fmt.Println("Start Counter") } func (*MyContext) StopCounter() { // Start Counter Code fmt.Println("Stop Counter") } func (*MyContext) ResetCounter() { // Start Counter Code fmt.Println("Reset Counter") } // /// Idle State type Idle struct { statechart.StateDefault[MyContext] } func (self *Idle) Setup(proxy statechart.StateSetupProxy[MyContext]) (statechart.EntryAction, statechart.ExitAction) { self.Init(proxy) // Add transition to Active state on ActivateEv event ( nil is for no action to take) statechart.AddSimpleStateTransition[ActivateEv, Active](proxy, nil) // return nil, nill because no action is needed for Enter and Exit return nil, nil } // /// Active State type Active struct { statechart.StateDefault[MyContext] } func (self *Active) Setup(proxy statechart.StateSetupProxy[MyContext]) (statechart.EntryAction, statechart.ExitAction) { self.Init(proxy) // Add transition to Idle state ( nil is for no action to take) statechart.AddSimpleStateTransition[DeactivateEv, Idle](proxy, nil) // Add transition to Active state ( nil is for no action to take) statechart.AddSimpleStateTransition[ResetEv, Active](proxy, nil) // Add starting State to Transition to activated (optional). only needed for super states // signature: AddStartingState[State](self) statechart.SetStartingState[Stopped](proxy) return self.Enter, nil } func (self *Active) Enter() { // Reset Counter Code self.GetContext().ResetCounter() } // /// Stopped State type Stopped struct { statechart.StateDefault[MyContext] } func (self *Stopped) Setup(proxy statechart.StateSetupProxy[MyContext]) (statechart.EntryAction, statechart.ExitAction) { self.Init(proxy) statechart.AddSimpleStateTransition[StartStopEv, Running](proxy, nil) return nil, nil } // /// Running State type Running struct { statechart.StateDefault[MyContext] } func (self *Running) Setup(proxy statechart.StateSetupProxy[MyContext]) (statechart.EntryAction, statechart.ExitAction) { self.Init(proxy) statechart.AddSimpleStateTransition[StartStopEv, Stopped](proxy, nil) return self.Enter, self.Exit } func (self *Running) Enter() { self.GetContext().StartCounter() } func (self *Running) Exit() { // Stop Counter Code self.GetContext().StopCounter() } func main() { // Create State Machine context := MyContext{} sm := statechart.MakeStateMachine(&context) idleState := sm.AddState(&Idle{}) activeState := sm.AddState(&Active{}) sm.AddSubState(&Stopped{}, activeState) sm.AddSubState(&Running{}, activeState) sm.Initialize(idleState) // example event dispatch sm.DispatchEvent(&ActivateEv{}) // go for Idle to Active to Stopped sm.DispatchEvent(&StartStopEv{}) // go from Stopped to Running sm.DispatchEvent(&ResetEv{}) // go from Running to Active to Stopped sm.DispatchEvent(&DeactivateEv{}) // go from Stopped to Idle }
Output: Reset Counter Start Counter Stop Counter Reset Counter
func MakeStateMachine ¶
func MakeStateMachine[C any](userContext_ *C) StateMachine[C]
Creates a state machine with a user context
func (*StateMachine[C]) AddState ¶
func (sm *StateMachine[C]) AddState(state State[C]) StateId
Adds a new State to the State Machine `state` the new state object to add returns the new stateId
func (*StateMachine[C]) AddSubState ¶
func (sm *StateMachine[C]) AddSubState(state State[C], parentId StateId) StateId
Adds a Sub-State to the State Machine `state` the new state object to add `parentId` the parent (super state) ID
func (*StateMachine[C]) DispatchEvent ¶
func (sm *StateMachine[C]) DispatchEvent(event Event)
Dispatches an events to the state machine `event` The Event to dispatch No error will occur if the Event is unknown to the state machine
func (*StateMachine[C]) GenerateUml ¶ added in v0.6.0
func (sm *StateMachine[C]) GenerateUml(w io.Writer, umlSyntax UmlSyntax, diagramType UmlDiagramType)
Generates the UML diagram for the state machine, using `w` the io stream writer `umlSyntax` the generator syntax only only support PlantUML syntax for now [https://plantuml.com/state-diagram] `diagramType` the type of diagram to use for the generation
func (*StateMachine[C]) Initialize ¶
func (sm *StateMachine[C]) Initialize(initStateId StateId)
Initializes the state machine `initStateId` the initial starting state
func (*StateMachine[C]) SetDebugLogger ¶
func (sm *StateMachine[C]) SetDebugLogger(logger func(msg string, keysAndValues ...interface{}))
Sets the Debug Trace Logger for the state machine
type StateProxy ¶
type StateProxy[C any] interface { // Returns the name of the State Name() string // Returns an ancestor of the current state GetAncestor(state StateId) State[C] // Returns the user context GetContext() *C // Find the StateId of a state in the state machine // It is ok to cache the stateId, to improve performance // `selector` a function that is used to test if a state is a match FindStateId(selector func(state State[C]) bool) StateId // Create a transition result (only needed for custom reactions) Transit(state StateId, action BaseAction) ReactionResult // Create a forward result (only needed for custom reactions) Forward() ReactionResult // Create a discard result (only needed for custom reactions) Discard() ReactionResult // Create a defer result (only needed for custom reactions) Defer() ReactionResult // Post an event to the event queue that will be processed after the current reaction PostEvent(event Event) }
StateProxy is a proxy for a state machine and state container. This is the main mechanisms to access the state machine
type StateSetupProxy ¶
type StateSetupProxy[C any] interface { StateProxy[C] // Set the name of the state ( the default name is from reflect.TypeOf().Name() ) SetName(string) // Add a state reaction AddReaction(reaction EventReaction) // Set a starting state (used for supper state) SetStartingState(state StateId) }
`StateSetupProxy` is a `StateProxy` that can add reactions and set the starting state.
type UmlDiagramType ¶ added in v0.6.0
type UmlDiagramType int16
const ( HIERARCHY_WITH_TRANSITION UmlDiagramType = iota HIERARCHY_ONLY FLAT_WITH_TRANSITION )
type UmlDocReaction ¶ added in v0.6.0
type UmlDocReaction struct { ReactionResult ResultType TargetState StateId ActionText string GuardText string }