fsm
packagemoduleThis package is not in the latest version of its module.
Details
Validgo.mod file
The Go module system was introduced in Go 1.11 and is the official dependency management solution for Go.
Redistributable license
Redistributable licenses place minimal restrictions on how software can be used, modified, and redistributed.
Tagged version
Modules with tagged versions give importers more predictable builds.
Stable version
When a project reaches major version v1 it is considered stable.
- Learn more about best practices
Repository
Links
README¶
FSM for Go
FSM is a finite state machine for Go.
It is heavily based on two FSM implementations:
Javascript Finite State Machine,https://github.com/jakesgordon/javascript-state-machine
Fysom for Python,https://github.com/oxplot/fysom (forked athttps://github.com/mriehl/fysom)
For API docs and examples seehttp://godoc.org/github.com/looplab/fsm
Basic Example
From examples/simple.go:
package mainimport ( "context" "fmt" "github.com/looplab/fsm")func main() { fsm := fsm.NewFSM( "closed", fsm.Events{ {Name: "open", Src: []string{"closed"}, Dst: "open"}, {Name: "close", Src: []string{"open"}, Dst: "closed"}, }, fsm.Callbacks{}, ) fmt.Println(fsm.Current()) err := fsm.Event(context.Background(), "open") if err != nil { fmt.Println(err) } fmt.Println(fsm.Current()) err = fsm.Event(context.Background(), "close") if err != nil { fmt.Println(err) } fmt.Println(fsm.Current())}Usage as a struct field
From examples/struct.go:
package mainimport ( "context" "fmt" "github.com/looplab/fsm")type Door struct { To string FSM *fsm.FSM}func NewDoor(to string) *Door { d := &Door{ To: to, } d.FSM = fsm.NewFSM( "closed", fsm.Events{ {Name: "open", Src: []string{"closed"}, Dst: "open"}, {Name: "close", Src: []string{"open"}, Dst: "closed"}, }, fsm.Callbacks{ "enter_state": func(_ context.Context, e *fsm.Event) { d.enterState(e) }, }, ) return d}func (d *Door) enterState(e *fsm.Event) { fmt.Printf("The door to %s is %s\n", d.To, e.Dst)}func main() { door := NewDoor("heaven") err := door.FSM.Event(context.Background(), "open") if err != nil { fmt.Println(err) } err = door.FSM.Event(context.Background(), "close") if err != nil { fmt.Println(err) }}License
FSM is licensed under Apache License 2.0
Documentation¶
Overview¶
Package fsm implements a finite state machine.
It is heavily based on two FSM implementations:
Javascript Finite State Machinehttps://github.com/jakesgordon/javascript-state-machine
Fysom for Pythonhttps://github.com/oxplot/fysom (forked athttps://github.com/mriehl/fysom)
Index¶
- func Visualize(fsm *FSM) string
- func VisualizeForMermaidWithGraphType(fsm *FSM, graphType MermaidDiagramType) (string, error)
- func VisualizeWithType(fsm *FSM, visualizeType VisualizeType) (string, error)
- type AsyncError
- type Callback
- type Callbacks
- type CanceledError
- type Event
- type EventDesc
- type Events
- type FSM
- func (f *FSM) AvailableTransitions() []string
- func (f *FSM) Can(event string) bool
- func (f *FSM) Cannot(event string) bool
- func (f *FSM) Current() string
- func (f *FSM) DeleteMetadata(key string)
- func (f *FSM) Event(ctx context.Context, event string, args ...interface{}) error
- func (f *FSM) Is(state string) bool
- func (f *FSM) Metadata(key string) (interface{}, bool)
- func (f *FSM) SetMetadata(key string, dataValue interface{})
- func (f *FSM) SetState(state string)
- func (f *FSM) Transition() error
- type InTransitionError
- type InternalError
- type InvalidEventError
- type MermaidDiagramType
- type NoTransitionError
- type NotInTransitionError
- type UnknownEventError
- type VisualizeType
Examples¶
Constants¶
This section is empty.
Variables¶
This section is empty.
Functions¶
funcVisualizeForMermaidWithGraphType¶added inv0.2.0
func VisualizeForMermaidWithGraphType(fsm *FSM, graphTypeMermaidDiagramType) (string,error)
VisualizeForMermaidWithGraphType outputs a visualization of a FSM in Mermaid format as specified by the graphType.
funcVisualizeWithType¶added inv0.2.0
func VisualizeWithType(fsm *FSM, visualizeTypeVisualizeType) (string,error)
VisualizeWithType outputs a visualization of a FSM in the desired format.If the type is not given it defaults to GRAPHVIZ
Types¶
typeAsyncError¶
AsyncError is returned by FSM.Event() when a callback have initiated anasynchronous state transition.
func (AsyncError)Error¶
func (eAsyncError) Error()string
func (AsyncError)Unwrap¶added inv1.0.3
func (eAsyncError) Unwrap()error
typeCallback¶
Callback is a function type that callbacks should use. Event is the currentevent info as the callback happens.
typeCanceledError¶
type CanceledError struct {Errerror}CanceledError is returned by FSM.Event() when a callback have canceled atransition.
func (CanceledError)Error¶
func (eCanceledError) Error()string
func (CanceledError)Unwrap¶added inv1.0.3
func (eCanceledError) Unwrap()error
typeEvent¶
type Event struct {// FSM is an reference to the current FSM.FSM *FSM// Event is the event name.Eventstring// Src is the state before the transition.Srcstring// Dst is the state after the transition.Dststring// Err is an optional error that can be returned from a callback.Errerror// Args is an optional list of arguments passed to the callback.Args []interface{}// contains filtered or unexported fields}Event is the info that get passed as a reference in the callbacks.
typeEventDesc¶
type EventDesc struct {// Name is the event name used when calling for a transition.Namestring// Src is a slice of source states that the FSM must be in to perform a// state transition.Src []string// Dst is the destination state that the FSM will be in if the transition// succeeds.Dststring}EventDesc represents an event when initializing the FSM.
The event can have one or more source states that is valid for performingthe transition. If the FSM is in one of the source states it will end up inthe specified destination state, calling all defined callbacks as it goes.
typeFSM¶
type FSM struct {// contains filtered or unexported fields}FSM is the state machine that holds the current state.
It has to be created with NewFSM to function properly.
funcNewFSM¶
NewFSM constructs a FSM from events and callbacks.
The events and transitions are specified as a slice of Event structsspecified as Events. Each Event is mapped to one or more internaltransitions from Event.Src to Event.Dst.
Callbacks are added as a map specified as Callbacks where the key is parsedas the callback event as follows, and called in the same order:
1. before_<EVENT> - called before event named <EVENT>
2. before_event - called before all events
3. leave_<OLD_STATE> - called before leaving <OLD_STATE>
4. leave_state - called before leaving all states
5. enter_<NEW_STATE> - called after entering <NEW_STATE>
6. enter_state - called after entering all states
7. after_<EVENT> - called after event named <EVENT>
8. after_event - called after all events
There are also two short form versions for the most commonly used callbacks.They are simply the name of the event or state:
1. <NEW_STATE> - called after entering <NEW_STATE>
2. <EVENT> - called after event named <EVENT>
If both a shorthand version and a full version is specified it is undefinedwhich version of the callback will end up in the internal map. This is dueto the pseudo random nature of Go maps. No checking for multiple keys iscurrently performed.
Example¶
fsm := NewFSM("green",Events{{Name: "warn", Src: []string{"green"}, Dst: "yellow"},{Name: "panic", Src: []string{"yellow"}, Dst: "red"},{Name: "panic", Src: []string{"green"}, Dst: "red"},{Name: "calm", Src: []string{"red"}, Dst: "yellow"},{Name: "clear", Src: []string{"yellow"}, Dst: "green"},},Callbacks{"before_warn": func(_ context.Context, e *Event) {fmt.Println("before_warn")},"before_event": func(_ context.Context, e *Event) {fmt.Println("before_event")},"leave_green": func(_ context.Context, e *Event) {fmt.Println("leave_green")},"leave_state": func(_ context.Context, e *Event) {fmt.Println("leave_state")},"enter_yellow": func(_ context.Context, e *Event) {fmt.Println("enter_yellow")},"enter_state": func(_ context.Context, e *Event) {fmt.Println("enter_state")},"after_warn": func(_ context.Context, e *Event) {fmt.Println("after_warn")},"after_event": func(_ context.Context, e *Event) {fmt.Println("after_event")},},)fmt.Println(fsm.Current())err := fsm.Event(context.Background(), "warn")if err != nil {fmt.Println(err)}fmt.Println(fsm.Current())Output:greenbefore_warnbefore_eventleave_greenleave_stateenter_yellowenter_stateafter_warnafter_eventyellow
func (*FSM)AvailableTransitions¶
AvailableTransitions returns a list of transitions available in thecurrent state.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},{Name: "kick", Src: []string{"closed"}, Dst: "broken"},},Callbacks{},)// sort the results ordering is consistent for the output checkertransitions := fsm.AvailableTransitions()sort.Strings(transitions)fmt.Println(transitions)Output:[kick open]
func (*FSM)Can¶
Can returns true if event can occur in the current state.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{},)fmt.Println(fsm.Can("open"))fmt.Println(fsm.Can("close"))Output:truefalse
func (*FSM)Cannot¶
Cannot returns true if event can not occur in the current state.It is a convenience method to help code read nicely.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{},)fmt.Println(fsm.Cannot("open"))fmt.Println(fsm.Cannot("close"))Output:falsetrue
func (*FSM)Current¶
Current returns the current state of the FSM.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{},)fmt.Println(fsm.Current())Output:closed
func (*FSM)DeleteMetadata¶added inv1.0.0
DeleteMetadata deletes the dataValue in metadata by key
func (*FSM)Event¶
Event initiates a state transition with the named event.
The call takes a variable number of arguments that will be passed to thecallback, if defined.
It will return nil if the state change is ok or one of these errors:
- event X inappropriate because previous transition did not complete
- event X inappropriate in current state Y
- event X does not exist
- internal error on state transition
The last error should never occur in this situation and is a sign of aninternal bug.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{},)fmt.Println(fsm.Current())err := fsm.Event(context.Background(), "open")if err != nil {fmt.Println(err)}fmt.Println(fsm.Current())err = fsm.Event(context.Background(), "close")if err != nil {fmt.Println(err)}fmt.Println(fsm.Current())Output:closedopenclosed
func (*FSM)Is¶
Is returns true if state is the current state.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{},)fmt.Println(fsm.Is("closed"))fmt.Println(fsm.Is("open"))Output:truefalse
func (*FSM)SetMetadata¶added inv0.3.0
SetMetadata stores the dataValue in metadata indexing it with key
func (*FSM)SetState¶
SetState allows the user to move to the given state from current state.The call does not trigger any callbacks, if defined.
func (*FSM)Transition¶
Transition wraps transitioner.transition.
Example¶
fsm := NewFSM("closed",Events{{Name: "open", Src: []string{"closed"}, Dst: "open"},{Name: "close", Src: []string{"open"}, Dst: "closed"},},Callbacks{"leave_closed": func(_ context.Context, e *Event) {e.Async()},},)err := fsm.Event(context.Background(), "open")if e, ok := err.(AsyncError); !ok && e.Err != nil {fmt.Println(err)}fmt.Println(fsm.Current())err = fsm.Transition()if err != nil {fmt.Println(err)}fmt.Println(fsm.Current())Output:closedopen
typeInTransitionError¶
type InTransitionError struct {Eventstring}InTransitionError is returned by FSM.Event() when an asynchronous transitionis already in progress.
func (InTransitionError)Error¶
func (eInTransitionError) Error()string
typeInternalError¶
type InternalError struct{}InternalError is returned by FSM.Event() and should never occur. It is aprobably because of a bug.
func (InternalError)Error¶
func (eInternalError) Error()string
typeInvalidEventError¶
InvalidEventError is returned by FSM.Event() when the event cannot be calledin the current state.
func (InvalidEventError)Error¶
func (eInvalidEventError) Error()string
typeMermaidDiagramType¶added inv0.2.0
type MermaidDiagramTypestring
MermaidDiagramType the type of the mermaid diagram type
const (// FlowChart the diagram type for output in flowchart style (https://mermaid-js.github.io/mermaid/#/flowchart) (including current state)FlowChartMermaidDiagramType = "flowChart"// StateDiagram the diagram type for output in stateDiagram style (https://mermaid-js.github.io/mermaid/#/stateDiagram)StateDiagramMermaidDiagramType = "stateDiagram")
typeNoTransitionError¶
type NoTransitionError struct {Errerror}NoTransitionError is returned by FSM.Event() when no transition have happened,for example if the source and destination states are the same.
func (NoTransitionError)Error¶
func (eNoTransitionError) Error()string
func (NoTransitionError)Unwrap¶added inv1.0.3
func (eNoTransitionError) Unwrap()error
typeNotInTransitionError¶
type NotInTransitionError struct{}NotInTransitionError is returned by FSM.Transition() when an asynchronoustransition is not in progress.
func (NotInTransitionError)Error¶
func (eNotInTransitionError) Error()string
typeUnknownEventError¶
type UnknownEventError struct {Eventstring}UnknownEventError is returned by FSM.Event() when the event is not defined.
func (UnknownEventError)Error¶
func (eUnknownEventError) Error()string
typeVisualizeType¶added inv0.2.0
type VisualizeTypestring
VisualizeType the type of the visualization
const (// GRAPHVIZ the type for graphviz output (http://www.webgraphviz.com/)GRAPHVIZVisualizeType = "graphviz"// MERMAID the type for mermaid output (https://mermaid-js.github.io/mermaid/#/stateDiagram) in the stateDiagram formMERMAIDVisualizeType = "mermaid"// MermaidStateDiagram the type for mermaid output (https://mermaid-js.github.io/mermaid/#/stateDiagram) in the stateDiagram formMermaidStateDiagramVisualizeType = "mermaid-state-diagram"// MermaidFlowChart the type for mermaid output (https://mermaid-js.github.io/mermaid/#/flowchart) in the flow chart formMermaidFlowChartVisualizeType = "mermaid-flow-chart")