Documentation
¶
Overview ¶
Package lfsm provides a light-weight lock-free state machine.
This state machine uses atomic operations to transition between states.
Basic Example:
package main import ( "log" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {1}, 1: {0}}) log.Printf("Current state: %s", s.Current()) // Current state: 1 if err := s.Transition(0); err != nil { panic(err) } log.Printf("Current state: %s", s.Current()) // Current state: 0 }
You may want to label your states, so the lfsm.StateNames struct and lfsm.StateName function can be used to supply options for the State Machine. For extra convenience you can use constants for your states. Named Example:
package main import ( "log" "github.com/Eyal-Shalev/lfsm" ) const ( opened uint64 = iota closed ) func main() { s := lfsm.NewState( lfsm.Constraints{ opened: {closed}, closed: {opened}, }, lfsm.StateNames{opened: "opened", closed: "closed"}, ) log.Printf("Current state: %s", s.Current()) // Current state: closed if err := s.Transition(0); err != nil { panic(err) } log.Printf("Current state: %s", s.Current()) // Current state: opened }
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InitialState ¶
func InitialState(v uint32) option
InitialState sets the initial state of the state machine
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {1}, 1: {0}}, lfsm.InitialState(1)) fmt.Printf("Current state: %d.\n", s.Current()) }
Output: Current state: 1.
Types ¶
type Constraints ¶
Constraints defines the possible transition for this state machine.
The map keys describe the source states, and their values are the valid target destinations.
type State ¶
type State struct {
// contains filtered or unexported fields
}
State is the structs that holds the current state, the available transitions and other options.
func NewState ¶
func NewState(m Constraints, opts ...option) *State
NewState creates a new State Machine.
func (*State) CurrentName ¶
CurrentName returns the alias for the current state. If no alias is defined, the state integer will be returned in its string version.
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {1}, 1: {0}}, lfsm.StateName(1, "foo")) fmt.Printf("Current state: %s(%d).\n", s.CurrentName(), s.Current()) _ = s.Transition(1) fmt.Printf("Current state: %s(%d).\n", s.CurrentName(), s.Current()) }
Output: Current state: 0(0). Current state: foo(1).
func (*State) String ¶
String returns the Graphviz representation of this state machine.
See: https://www.graphviz.org/ & https://dreampuf.github.io/GraphvizOnline
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { fmt.Println(lfsm.NewState(lfsm.Constraints{0: {0}}, lfsm.StateNames{0: "foo"})) }
Output: digraph g{s[label="",shape=none,height=.0,width=.0];s->n0;n0[label="foo",style=filled];n0->n0;}
func (*State) Transition ¶
Transition tries to change the state. It uses the current state as the source state, if you want to specify the source state use TransitionFrom instead. Returns an error if the transition failed.
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {0, 1}, 1: {0}}, lfsm.InitialState(1)) err := s.Transition(1) fmt.Printf("Expected error: %s.\n", err) err = s.Transition(0) if err != nil { panic(err) } fmt.Printf("Current state: %d.\n", s.Current()) err = s.Transition(0) if err != nil { panic(err) } fmt.Printf("Current state: %d.\n", s.Current()) err = s.Transition(1) if err != nil { panic(err) } fmt.Printf("Current state: %d.\n", s.Current()) }
Output: Expected error: invalid transition (1 -> 1). Current state: 0. Current state: 0. Current state: 1.
func (*State) TransitionFrom ¶
TransitionFrom tries to change the state. Returns an error if the transition failed.
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {1}, 1: {0}}, lfsm.InitialState(1)) err := s.TransitionFrom(0, 1) fmt.Printf("Expected error: %s.\n", err) err = s.TransitionFrom(1, 0) if err != nil { panic(err) } fmt.Printf("Current state: %d.\n", s.Current()) }
Output: Expected error: transition failed (0 -> 1) current state is not 0. Current state: 0.
type StateNames ¶
StateNames holds a mapping between the state (in its integer form) to its alias.
Example ¶
package main import ( "fmt" "github.com/Eyal-Shalev/lfsm" ) func main() { s := lfsm.NewState(lfsm.Constraints{0: {}}, lfsm.StateNames{0: "foo"}) fmt.Printf("Current state: %s(%d).\n", s.CurrentName(), s.Current()) }
Output: Current state: foo(0).
type TransitionError ¶
type TransitionError struct {
Src, Dst uint32
// contains filtered or unexported fields
}
TransitionError is an error struct for all failed transition attempts.
func NewFailedTransitionError ¶
func NewFailedTransitionError(src, dst uint32, stateNames StateNames) *TransitionError
NewFailedTransitionError reports that the current state differs from the transition source state.
func NewInvalidTransitionError ¶
func NewInvalidTransitionError(src, dst uint32, stateNames StateNames) *TransitionError
NewFailedTransitionError reports about a transition attempt that was not defined in the Constraints map.
func (*TransitionError) DstName ¶
func (f *TransitionError) DstName() string
func (*TransitionError) Error ¶
func (f *TransitionError) Error() string
func (*TransitionError) SrcName ¶
func (f *TransitionError) SrcName() string