Documentation ¶
Overview ¶
Package fsm implements a finite state machine.
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 at https://github.com/mriehl/fysom)
Index ¶
- Variables
- func Visualize(fsm *FSM) string
- type AsyncError
- type Callback
- type Callbacks
- type CanceledError
- type Event
- type EventDesc
- type Events
- type FSM
- type InTransitionError
- type InternalError
- type InvalidEventError
- type NoTransitionError
- type NotInTransitionError
- type RelationEvent
- type RelationEventHandler
- type RelationState
- type RelationStateMachine
- type UnknownEventError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // states StateNoRelation = RelationState("no_relation") StateWhisper = RelationState("whisper") StateFollowing = RelationState("following") StateBlacked = RelationState("blacked") StateFriend = RelationState("friend") // StateFriend is the most special state // events EventAddFollowing = RelationEvent("add_following") EventDelFollowing = RelationEvent("del_following") EventAddWhisper = RelationEvent("add_whisper") EventDelWhisper = RelationEvent("del_whisper") EventAddBlack = RelationEvent("add_black") EventDelBlack = RelationEvent("del_black") EventDelFollower = RelationEvent("del_follower") EventBeFriend = RelationEvent("be_friend") // EventBeFriend is the most special event )
consts for relation
var DefaultHandler = &defaultHandlerImpl{}
DefaultHandler is the default RelationEventHandler
Functions ¶
Types ¶
type AsyncError ¶
type AsyncError struct {
Err error
}
AsyncError is returned by FSM.Event() when a callback have initiated an asynchronous state transition.
func (AsyncError) Error ¶
func (e AsyncError) Error() string
type Callback ¶
type Callback func(*Event)
Callback is a function type that callbacks should use. Event is the current event info as the callback happens.
type CanceledError ¶
type CanceledError struct {
Err error
}
CanceledError is returned by FSM.Event() when a callback have canceled a transition.
func (CanceledError) Error ¶
func (e CanceledError) Error() string
type Event ¶
type Event struct { // FSM is a reference to the current FSM. FSM *FSM // Event is the event name. Event string // Src is the state before the transition. Src string // Dst is the state after the transition. Dst string // Err is an optional error that can be returned from a callback. Err error // Args is a optinal 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.
type EventDesc ¶
type EventDesc struct { // Name is the event name used when calling for a transition. Name string // 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 // succeds. Dst string }
EventDesc represents an event when initializing the FSM.
The event can have one or more source states that is valid for performing the transition. If the FSM is in one of the source states it will end up in the specified destination state, calling all defined callbacks as it goes.
type Events ¶
type Events []EventDesc
Events is a shorthand for defining the transition map in NewFSM.
type FSM ¶
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.
func NewFSM ¶
NewFSM constructs a FSM from events and callbacks.
The events and transitions are specified as a slice of Event structs specified as Events. Each Event is mapped to one or more internal transitions from Event.Src to Event.Dst.
Callbacks are added as a map specified as Callbacks where the key is parsed as 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 undefined which version of the callback will end up in the internal map. This is due to the psuedo random nature of Go maps. No checking for multiple keys is currently 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(e *Event) { fmt.Println("before_warn") }, "before_event": func(e *Event) { fmt.Println("before_event") }, "leave_green": func(e *Event) { fmt.Println("leave_green") }, "leave_state": func(e *Event) { fmt.Println("leave_state") }, "enter_yellow": func(e *Event) { fmt.Println("enter_yellow") }, "enter_state": func(e *Event) { fmt.Println("enter_state") }, "after_warn": func(e *Event) { fmt.Println("after_warn") }, "after_event": func(e *Event) { fmt.Println("after_event") }, }, ) fmt.Println(fsm.Current()) err := fsm.Event("warn") if err != nil { fmt.Println(err) } fmt.Println(fsm.Current())
Output: green before_warn before_event leave_green leave_state enter_yellow enter_state after_warn after_event yellow
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: true false
func (*FSM) Cannot ¶
Cannot returns true if event can not occure 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: false true
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) Event ¶
Event initiates a state transition with the named event.
The call takes a variable number of arguments that will be passed to the callback, 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 an internal 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("open") if err != nil { fmt.Println(err) } fmt.Println(fsm.Current()) err = fsm.Event("close") if err != nil { fmt.Println(err) } fmt.Println(fsm.Current())
Output: closed open closed
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: true false
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(e *Event) { e.Async() }, }, ) err := fsm.Event("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: closed open
type InTransitionError ¶
type InTransitionError struct {
Event string
}
InTransitionError is returned by FSM.Event() when an asynchronous transition is already in progress.
func (InTransitionError) Error ¶
func (e InTransitionError) Error() string
type InternalError ¶
type InternalError struct{}
InternalError is returned by FSM.Event() and should never occur. It is a probably because of a bug.
func (InternalError) Error ¶
func (e InternalError) Error() string
type InvalidEventError ¶
InvalidEventError is returned by FSM.Event() when the event cannot be called in the current state.
func (InvalidEventError) Error ¶
func (e InvalidEventError) Error() string
type NoTransitionError ¶
type NoTransitionError struct {
Err error
}
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 (e NoTransitionError) Error() string
type NotInTransitionError ¶
type NotInTransitionError struct{}
NotInTransitionError is returned by FSM.Transition() when an asynchronous transition is not in progress.
func (NotInTransitionError) Error ¶
func (e NotInTransitionError) Error() string
type RelationEventHandler ¶
type RelationEventHandler interface { AddFollowing(*Event) DelFollowing(*Event) AddWhisper(*Event) DelWhisper(*Event) AddBlack(*Event) DelBlack(*Event) DelFollower(*Event) }
RelationEventHandler is used to handle all state change for relation
type RelationStateMachine ¶
type RelationStateMachine struct {
*FSM
}
RelationStateMachine is used to describe all state change for relation
func NewRelationStateMachine ¶
func NewRelationStateMachine(initial RelationState, handler RelationEventHandler) *RelationStateMachine
NewRelationStateMachine will create a RelationStateMachine
func (*RelationStateMachine) Event ¶
func (r *RelationStateMachine) Event(event RelationEvent, args ...interface{}) error
Event is used to execute any events
func (*RelationStateMachine) SetState ¶
func (r *RelationStateMachine) SetState(state RelationState)
SetState is used to set state
type UnknownEventError ¶
type UnknownEventError struct {
Event string
}
UnknownEventError is returned by FSM.Event() when the event is not defined.
func (UnknownEventError) Error ¶
func (e UnknownEventError) Error() string