Documentation ¶
Overview ¶
Package machine is a general purpose state machine for managing complex async workflows in a safe and structured way.
It's a dependency-free implementation of AsyncMachine in Golang using channels and context. It aims at simplicity and speed.
Index ¶
- Constants
- Variables
- func IsActiveTick(tick uint64) bool
- func IsHandler(states S, method string) (string, string)
- func IsTimeAfter(time1, time2 Time) bool
- func ListHandlers(handlers any, states S) ([]string, error)
- func MockClock(mach *Machine, clock Clock)
- func NewArgsMapper(names []string, maxlen int) func(args A) map[string]string
- func NewStateGroups[G any](groups G, mixins ...any) G
- func NewStates[G States](states G) G
- func StatesEqual(states1 S, states2 S) bool
- type A
- type AT
- type Api
- type Clock
- type CtxBinding
- type CtxKeyName
- type CtxValue
- type DefaultRelationsResolver
- func (rr *DefaultRelationsResolver) GetAutoMutation() *Mutation
- func (rr *DefaultRelationsResolver) GetRelationsBetween(fromState, toState string) ([]Relation, error)
- func (rr *DefaultRelationsResolver) GetRelationsOf(fromState string) ([]Relation, error)
- func (rr *DefaultRelationsResolver) GetTargetStates(t *Transition, calledStates S) S
- func (rr *DefaultRelationsResolver) NewStruct()
- func (rr *DefaultRelationsResolver) SortStates(states S)
- type Event
- type ExceptionArgsPanic
- type ExceptionHandler
- type HandlerFinal
- type HandlerNegotiation
- type IndexStateCtx
- type IndexWhen
- type IndexWhenArgs
- type IndexWhenTime
- type LogArgsMapper
- type LogEntry
- type LogLevel
- type Logger
- type Machine
- func (m *Machine) ActiveStates() S
- func (m *Machine) Add(states S, args A) Result
- func (m *Machine) Add1(state string, args A) Result
- func (m *Machine) AddBreakpoint(added S, removed S)
- func (m *Machine) AddErr(err error, args A) Result
- func (m *Machine) AddErrState(state string, err error, args A) Result
- func (m *Machine) AddFromEv(states S, event *Event, args A) Result
- func (m *Machine) Any(states ...S) bool
- func (m *Machine) Any1(states ...string) bool
- func (m *Machine) BindHandlers(handlers any) error
- func (m *Machine) BindTracer(tracer Tracer)
- func (m *Machine) CanAdd(states S) bool
- func (m *Machine) CanRemove(states S) bool
- func (m *Machine) CanSet(states S) bool
- func (m *Machine) Clock(states S) Clock
- func (m *Machine) CountActive(states S) int
- func (m *Machine) Ctx() context.Context
- func (m *Machine) DetachHandlers(handlers any) error
- func (m *Machine) DetachTracer(tracer Tracer) bool
- func (m *Machine) Dispose()
- func (m *Machine) DisposeForce()
- func (m *Machine) Err() error
- func (m *Machine) Eval(source string, fn func(), ctx context.Context) bool
- func (m *Machine) Export() *Serialized
- func (m *Machine) GetLogArgs() LogArgsMapper
- func (m *Machine) GetLogId() bool
- func (m *Machine) GetLogLevel() LogLevel
- func (m *Machine) GetLogger() *Logger
- func (m *Machine) GetStruct() Struct
- func (m *Machine) Has(states S) bool
- func (m *Machine) Has1(state string) bool
- func (m *Machine) Id() string
- func (m *Machine) Import(data *Serialized) error
- func (m *Machine) Index(state string) int
- func (m *Machine) Inspect(states S) string
- func (m *Machine) Is(states S) bool
- func (m *Machine) Is1(state string) bool
- func (m *Machine) IsClock(clock Clock) bool
- func (m *Machine) IsDisposed() bool
- func (m *Machine) IsErr() bool
- func (m *Machine) IsQueued(mutationType MutationType, states S, withoutArgsOnly bool, ...) int
- func (m *Machine) IsTime(t Time, states S) bool
- func (m *Machine) Log(msg string, args ...any)
- func (m *Machine) LogLvl(lvl LogLevel, msg string, args ...any)
- func (m *Machine) MustBindHandlers(handlers any)
- func (m *Machine) MustParseStates(states S) S
- func (m *Machine) NewStateCtx(state string) context.Context
- func (m *Machine) Not(states S) bool
- func (m *Machine) Not1(state string) bool
- func (m *Machine) PanicToErr(args A)
- func (m *Machine) PanicToErrState(state string, args A)
- func (m *Machine) ParentId() string
- func (m *Machine) Queue() []*Mutation
- func (m *Machine) RegisterDisposalHandler(fn func())
- func (m *Machine) Remove(states S, args A) Result
- func (m *Machine) Remove1(state string, args A) Result
- func (m *Machine) RemoveFromEv(states S, event *Event, args A) Result
- func (m *Machine) Resolver() RelationsResolver
- func (m *Machine) Set(states S, args A) Result
- func (m *Machine) SetFromEv(states S, event *Event, args A) Result
- func (m *Machine) SetLogArgs(mapper LogArgsMapper)
- func (m *Machine) SetLogId(val bool)
- func (m *Machine) SetLogLevel(level LogLevel)
- func (m *Machine) SetLogger(fn Logger)
- func (m *Machine) SetLoggerEmpty(level LogLevel)
- func (m *Machine) SetLoggerSimple(logf func(format string, args ...any), level LogLevel)
- func (m *Machine) SetStruct(statesStruct Struct, names S) error
- func (m *Machine) StateNames() S
- func (m *Machine) StatesVerified() bool
- func (m *Machine) String() string
- func (m *Machine) StringAll() string
- func (m *Machine) Switch(groups ...S) string
- func (m *Machine) Tick(state string) uint64
- func (m *Machine) Time(states S) Time
- func (m *Machine) TimeSum(states S) uint64
- func (m *Machine) Toggle1(state string) Result
- func (m *Machine) Tracers() []Tracer
- func (m *Machine) Transition() *Transition
- func (m *Machine) VerifyStates(states S) error
- func (m *Machine) When(states S, ctx context.Context) <-chan struct{}
- func (m *Machine) When1(state string, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenArgs(state string, args A, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenDisposed() <-chan struct{}
- func (m *Machine) WhenErr(disposeCtx context.Context) <-chan struct{}
- func (m *Machine) WhenNot(states S, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenNot1(state string, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenQueueEnds(ctx context.Context) <-chan struct{}
- func (m *Machine) WhenTicks(state string, ticks int, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenTicksEq(state string, ticks uint64, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenTime(states S, times Time, ctx context.Context) <-chan struct{}
- func (m *Machine) WillBe(states S) bool
- func (m *Machine) WillBe1(state string) bool
- func (m *Machine) WillBeRemoved(states S) bool
- func (m *Machine) WillBeRemoved1(state string) bool
- type Mutation
- type MutationType
- type NoOpTracer
- func (t *NoOpTracer) HandlerEnd(transition *Transition, emitter string, handler string)
- func (t *NoOpTracer) HandlerStart(transition *Transition, emitter string, handler string)
- func (t *NoOpTracer) Inheritable() bool
- func (t *NoOpTracer) MachineDispose(machID string)
- func (t *NoOpTracer) MachineInit(machine Api) context.Context
- func (t *NoOpTracer) NewSubmachine(parent, machine Api)
- func (t *NoOpTracer) QueueEnd(machine Api)
- func (t *NoOpTracer) StructChange(machine Api, old Struct)
- func (t *NoOpTracer) TransitionEnd(transition *Transition)
- func (t *NoOpTracer) TransitionInit(transition *Transition)
- func (t *NoOpTracer) TransitionStart(transition *Transition)
- func (t *NoOpTracer) VerifyStates(machine Api)
- type Opts
- type Relation
- type RelationsResolver
- type Result
- type S
- type Serialized
- type State
- type StateIsActive
- type States
- type StatesBase
- type Step
- type StepType
- type Struct
- type Time
- type Tracer
- type Transition
- func (t *Transition) Args() A
- func (t *Transition) CalledStates() S
- func (t *Transition) ClockAfter() Clock
- func (t *Transition) ClockBefore() Clock
- func (t *Transition) IsAuto() bool
- func (t *Transition) IsCompleted() bool
- func (t *Transition) LogArgs() string
- func (t *Transition) StatesBefore() S
- func (t *Transition) String() string
- func (t *Transition) TargetStates() S
- func (t *Transition) Type() MutationType
- type WhenArgsBinding
- type WhenBinding
- type WhenTimeBinding
Examples ¶
Constants ¶
const ( // Exception is a name the Exception state. Exception = "Exception" // Any is a name of a meta state used in catch-all handlers. Any = "Any" )
const ( // EnvAmDebug enables a simple debugging mode (eg long timeouts). // "1" | "2" | "" (default) EnvAmDebug = "AM_DEBUG" // EnvAmLog sets the log level. // "1" | "2" | "3" | "4" | "" (default) EnvAmLog = "AM_LOG" // EnvAmLogFile enables file logging (use machine ID as name). // "1" | "" (default) EnvAmLogFile = "AM_LOG_FILE" // EnvAmDetectEval detects evals directly in handlers (use in tests). EnvAmDetectEval = "AM_DETECT_EVAL" // EnvAmTraceFilter will remove its contents from stack traces, making them // shorter. EnvAmTraceFilter = "AM_TRACE_FILTER" // EnvAmTestDebug activates debugging in tests. EnvAmTestDebug = "AM_TEST_DEBUG" // HandlerGlobal is the name of a global transition handler. HandlerGlobal = "AnyAny" )
Variables ¶
var ( // ErrStateUnknown indicates that the state is unknown. ErrStateUnknown = errors.New("state unknown") // ErrCanceled can be used to indicate a canceled Transition. ErrCanceled = errors.New("transition canceled") // ErrQueued can be used to indicate a queued Transition. ErrQueued = errors.New("transition queued") // ErrInvalidArgs can be used to indicate invalid arguments. ErrInvalidArgs = errors.New("invalid arguments") // ErrHandlerTimeout can be used to indicate timed out mutation. ErrHandlerTimeout = errors.New("handler timeout") // ErrTimeout can be used to indicate a timeout. ErrTimeout = errors.New("timeout") // ErrStateMissing is used to indicate missing states. ErrStateMissing = errors.New("missing states") // ErrRelation is used to indicate a relation definition error. ErrRelation = errors.New("relation error") // ErrDisposed is used to indicate that the machine has been disposed. ErrDisposed = errors.New("machine disposed") )
var CtxKey = &CtxKeyName{}
var LogArgs = []string{"name", "id", "port", "addr"}
LogArgs is a list of common argument names to be logged. Useful for debugging.
Functions ¶
func IsActiveTick ¶ added in v0.5.0
IsActiveTick returns true if the tick represents an active state (odd number).
func IsHandler ¶ added in v0.8.0
IsHandler checks if a method name is a handler method, by returning a state name.
func IsTimeAfter ¶
IsTimeAfter checks if time1 is after time2. Requires a deterministic states order, e.g. by using Machine.VerifyStates.
func ListHandlers ¶ added in v0.8.0
ListHandlers returns a list of handler method names from a handlers struct.
func MockClock ¶ added in v0.7.0
MockClock mocks the internal clock of the machine. Only for testing.
func NewArgsMapper ¶ added in v0.5.0
NewArgsMapper returns a matcher function for LogArgs. Useful for debugging untyped argument maps.
maxlen: maximum length of the string representation of the argument (default=20).
func NewStateGroups ¶ added in v0.8.0
func StatesEqual ¶ added in v0.8.0
Types ¶
type A ¶
A (arguments) is a map of named arguments for a Mutation.
type AT ¶ added in v0.8.0
type AT struct { Err error ErrTrace string Panic *ExceptionArgsPanic }
AT represents typed arguments of pkg/machine, extracted from Event.Args via ParseArgs, or created manually to for Pass.
type Api ¶ added in v0.8.0
type Api interface { Add1(state string, args A) Result Add(states S, args A) Result Remove1(state string, args A) Result Remove(states S, args A) Result Set(states S, args A) Result AddErr(err error, args A) Result AddErrState(state string, err error, args A) Result WhenArgs(state string, args A, ctx context.Context) <-chan struct{} Err() error IsErr() bool Is(states S) bool Is1(state string) bool Not(states S) bool Not1(state string) bool Any(states ...S) bool Any1(state ...string) bool Has(states S) bool Has1(state string) bool IsTime(time Time, states S) bool IsClock(clock Clock) bool When(states S, ctx context.Context) <-chan struct{} When1(state string, ctx context.Context) <-chan struct{} WhenNot(states S, ctx context.Context) <-chan struct{} WhenNot1(state string, ctx context.Context) <-chan struct{} WhenTime( states S, times Time, ctx context.Context) <-chan struct{} WhenTicks(state string, ticks int, ctx context.Context) <-chan struct{} WhenTicksEq(state string, tick uint64, ctx context.Context) <-chan struct{} WhenErr(ctx context.Context) <-chan struct{} StateNames() S ActiveStates() S Tick(state string) uint64 Clock(states S) Clock Time(states S) Time TimeSum(states S) uint64 NewStateCtx(state string) context.Context Export() *Serialized GetStruct() Struct Switch(groups ...S) string Log(msg string, args ...any) Id() string ParentId() string SetLogId(val bool) GetLogId() bool SetLogger(logger Logger) SetLogLevel(lvl LogLevel) SetLoggerEmpty(lvl LogLevel) SetLoggerSimple(logf func(format string, args ...any), level LogLevel) Ctx() context.Context String() string StringAll() string Inspect(states S) string Index(state string) int BindHandlers(handlers any) error StatesVerified() bool Tracers() []Tracer DetachTracer(tracer Tracer) bool BindTracer(tracer Tracer) Dispose() WhenDisposed() <-chan struct{} IsDisposed() bool }
Api is a subset of Machine for alternative implementations.
type Clock ¶ added in v0.7.0
Clock is a map of state names to their clock tick values. It's like Time, but indexed by string, instead of int.
type CtxBinding ¶ added in v0.8.0
type CtxBinding struct { Ctx context.Context Cancel context.CancelFunc }
type CtxKeyName ¶ added in v0.8.0
type CtxKeyName struct{}
type DefaultRelationsResolver ¶
type DefaultRelationsResolver struct { Machine *Machine Transition *Transition // contains filtered or unexported fields }
DefaultRelationsResolver is the default implementation of the RelationsResolver with Add, Remove, Require and After. It can be overridden using Opts.Resolver.
func (*DefaultRelationsResolver) GetAutoMutation ¶
func (rr *DefaultRelationsResolver) GetAutoMutation() *Mutation
GetAutoMutation implements RelationsResolver.GetAutoMutation.
func (*DefaultRelationsResolver) GetRelationsBetween ¶ added in v0.5.0
func (rr *DefaultRelationsResolver) GetRelationsBetween( fromState, toState string, ) ([]Relation, error)
GetRelationsBetween returns a list of directional relation types between the given states. Not thread safe.
func (*DefaultRelationsResolver) GetRelationsOf ¶ added in v0.5.0
func (rr *DefaultRelationsResolver) GetRelationsOf(fromState string) ( []Relation, error, )
GetRelationsOf returns a list of relation types of the given state. Not thread safe.
func (*DefaultRelationsResolver) GetTargetStates ¶
func (rr *DefaultRelationsResolver) GetTargetStates( t *Transition, calledStates S, ) S
GetTargetStates implements RelationsResolver.GetTargetStates.
func (*DefaultRelationsResolver) NewStruct ¶ added in v0.8.0
func (rr *DefaultRelationsResolver) NewStruct()
func (*DefaultRelationsResolver) SortStates ¶
func (rr *DefaultRelationsResolver) SortStates(states S)
SortStates implements RelationsResolver.SortStates.
type Event ¶
type Event struct { // Name of the event / handler Name string // Machine is the machine that the event belongs to, it can be used to access // the current Transition and Mutation. Machine *Machine // Args is a map of named arguments for a Mutation. Args A // contains filtered or unexported fields }
Event struct represents a single event of a Mutation within a Transition. One event can have 0-n handlers.
func (*Event) Transition ¶ added in v0.5.0
func (e *Event) Transition() *Transition
Transition returns the Transition of an Event.
type ExceptionArgsPanic ¶
type ExceptionArgsPanic struct { CalledStates S StatesBefore S Transition *Transition LastStep *Step StackTrace string }
ExceptionArgsPanic is an optional argument ["panic"] for the Exception state which describes a panic within a Transition handler.
type ExceptionHandler ¶
type ExceptionHandler struct{}
ExceptionHandler provide a basic Exception state support, as should be embedded into handler structs in most of the cases.
func (*ExceptionHandler) ExceptionState ¶
func (eh *ExceptionHandler) ExceptionState(e *Event)
ExceptionState is a final entry handler for the Exception state. Args: - err error: The error that caused the Exception state. - panic *ExceptionArgsPanic: Optional details about the panic.
type HandlerFinal ¶ added in v0.8.0
type HandlerFinal func(*Event)
HandlerFinal TODO support in BindHandlers
type HandlerNegotiation ¶ added in v0.8.0
HandlerNegotiation TODO support in BindHandlers
type IndexStateCtx ¶ added in v0.7.0
type IndexStateCtx map[string]*CtxBinding
IndexStateCtx is a map of (single) state names to a context cancel function
type IndexWhen ¶ added in v0.7.0
type IndexWhen map[string][]*WhenBinding
IndexWhen is a map of (single) state names to a list of activation or de-activation bindings
type IndexWhenArgs ¶ added in v0.7.0
type IndexWhenArgs map[string][]*WhenArgsBinding
IndexWhenArgs is a map of (single) state names to a list of args value bindings
type IndexWhenTime ¶ added in v0.7.0
type IndexWhenTime map[string][]*WhenTimeBinding
IndexWhenTime is a map of (single) state names to a list of time bindings
type LogArgsMapper ¶ added in v0.8.0
LogArgsMapper is a function that maps arguments to be logged. Useful for debugging.
type LogLevel ¶
type LogLevel int
LogLevel enum
const ( // LogNothing means no logging, including external msgs. LogNothing LogLevel = iota // LogChanges means logging state changes and external msgs. LogChanges // LogOps means LogChanges + logging all the operations. LogOps // LogDecisions means LogOps + logging all the decisions behind them. LogDecisions // LogEverything means LogDecisions + all event and handler names, and more. LogEverything )
TODO add LogOpsSubs (30), spread log level 0 - 10 - 20 - 30 - 40
func EnvLogLevel ¶ added in v0.7.0
EnvLogLevel returns a log level from an environment variable, AM_LOG by default.
type Machine ¶
type Machine struct { // Time for a handler to execute. Default: 100ms. See Opts.HandlerTimeout. HandlerTimeout time.Duration // If true, the machine will print all exceptions to stdout. Default: true. // Requires an ExceptionHandler binding and Machine.PanicToException set. LogStackTrace bool // If true, the machine will catch panic and trigger the Exception state. // Default: true. PanicToException bool // Maximum number of mutations that can be queued. Default: 1000. QueueLimit int // If true, the machine has been Disposed and is no-op. Read-only. Disposed atomic.Bool // contains filtered or unexported fields }
Machine represent states, provides mutation methods, helpers methods and info about the current and scheduled transitions (if any).
func New ¶
New creates a new Machine instance, bound to context and modified with optional Opts.
Example ¶
t := &testing.T{} // Replace this with actual *testing.Time in real test cases initialState := S{"A"} mach := NewNoRels(t, initialState) // machine mach ready _ = mach
Output:
func NewCommon ¶ added in v0.5.0
func NewCommon( ctx context.Context, id string, statesStruct Struct, stateNames S, handlers any, parent Api, opts *Opts, ) (*Machine, error)
NewCommon creates a new Machine instance with all the common options set.
Example ¶
t := &testing.T{} // Replace this with actual *testing.Time in real test cases initialState := S{"A"} mach := NewNoRels(t, initialState) // machine mach ready _ = mach
Output:
func (*Machine) ActiveStates ¶
ActiveStates returns a copy of the currently active states.
func (*Machine) Add ¶
Add activates a list of states in the machine, returning the result of the transition (Executed, Queued, Canceled). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) Add1 ¶ added in v0.5.0
Add1 is a shorthand method to add a single state with the passed args.
func (*Machine) AddBreakpoint ¶ added in v0.8.0
AddBreakpoint adds a breakpoint for an outcome of mutation (added and removed states). Once such mutation happens, a log message will be printed out. You can set an IDE's breakpoint on this line and see the mutation's sync stack trace. When Machine.LogStackTrace is set, the stack trace will be printed out as well. Many breakpoints can be added, but none removed.
func (*Machine) AddErr ¶
AddErr is a dedicated method to add the Exception state with the passed error and optional arguments. Like every mutation method, it will resolve relations and trigger handlers. AddErr produces a stack trace of the error, if LogStackTrace is enabled.
func (*Machine) AddErrState ¶ added in v0.7.0
AddErrState adds a dedicated error state, along with the build in Exception state. Like every mutation method, it will resolve relations and trigger handlers. AddErrState produces a stack trace of the error, if LogStackTrace is enabled.
func (*Machine) AddFromEv ¶ added in v0.5.0
AddFromEv - planned. TODO AddFromEv TODO AddFromCtx using state ctx?
func (*Machine) Any ¶
Any is group call to Is, returns true if any of the params return true from Is.
machine.StringAll() // ()[Foo:0 Bar:0 Baz:0] machine.Add(S{"Foo"}) // is(Foo, Bar) or is(Bar) machine.Any(S{"Foo", "Bar"}, S{"Bar"}) // false // is(Foo) or is(Bar) machine.Any(S{"Foo"}, S{"Bar"}) // true
func (*Machine) Any1 ¶ added in v0.5.0
Any1 is group call to Is1(), returns true if any of the params return true from Is1().
func (*Machine) BindHandlers ¶
BindHandlers binds a struct of handler methods to the machine's states. Returns a HandlerBinding object, which signals when the binding is ready. Does not bind to embedded structs.
func (*Machine) BindTracer ¶ added in v0.8.0
func (*Machine) Clock ¶
Clock returns current machine's clock, a state-keyed map of ticks. If states are passed, only the ticks of the passed states are returned.
func (*Machine) CountActive ¶ added in v0.8.0
CountActive returns the amount of active states from a passed list. Useful for state groups.
func (*Machine) DetachHandlers ¶ added in v0.8.0
func (*Machine) DetachTracer ¶ added in v0.8.0
DetachTracer tries to remove a tracer from the machine. Returns true if the tracer was found and removed.
func (*Machine) Dispose ¶
func (m *Machine) Dispose()
Dispose disposes the machine and all its emitters. You can wait for the completion of the disposal with `<-mach.WhenDisposed`.
func (*Machine) DisposeForce ¶ added in v0.5.0
func (m *Machine) DisposeForce()
DisposeForce disposes the machine and all its emitters, without waiting for the queue to drain. Will cause panics.
func (*Machine) Eval ¶ added in v0.5.0
Eval executes a function on the machine's queue, allowing to avoid using locks for non-handler code. Blocking code should NOT be scheduled here. Eval cannot be called within a handler's critical section, as both are using the same serial queue and will deadlock. Eval has a timeout of HandlerTimeout/2 and will return false in case it happens.
ctx: nil context defaults to machine's context.
Note: usage of Eval is discouraged. But if you have to, use AM_DETECT_EVAL in tests for deadlock detection. Most usages of eval can be replaced with atomics.
func (*Machine) Export ¶ added in v0.6.4
func (m *Machine) Export() *Serialized
Export exports the machine state: id, time and state names.
func (*Machine) GetLogArgs ¶ added in v0.5.0
func (m *Machine) GetLogArgs() LogArgsMapper
GetLogArgs returns the current log args function.
func (*Machine) GetLogId ¶ added in v0.8.0
GetLogId returns the current state of the log id setting.
func (*Machine) GetLogLevel ¶ added in v0.3.0
GetLogLevel returns the log level of the machine.
func (*Machine) GetLogger ¶ added in v0.3.0
GetLogger returns the current custom logger function, or nil.
func (*Machine) Has ¶
Has return true is passed states are registered in the machine. Useful for checking if a machine implements specific state set.
func (*Machine) Has1 ¶ added in v0.5.0
Has1 is a shorthand for Has. It returns true if the passed state is registered in the machine.
func (*Machine) Import ¶ added in v0.6.4
func (m *Machine) Import(data *Serialized) error
Import imports the machine state: id, time and state names. It's not safe to import into a machine which has already produces transitions and/or has telemetry connected.
func (*Machine) Index ¶ added in v0.7.0
Index returns the index of a state in the machine's StateNames() list.
func (*Machine) Inspect ¶
Inspect returns a multi-line string representation of the machine (states, relations, clocks). states: param for ordered or partial results.
func (*Machine) Is ¶
Is checks if all the passed states are currently active.
machine.StringAll() // ()[Foo:0 Bar:0 Baz:0] machine.Add(S{"Foo"}) machine.Is(S{"Foo"}) // true machine.Is(S{"Foo", "Bar"}) // false
func (*Machine) Is1 ¶ added in v0.5.0
Is1 is a shorthand method to check if a single state is currently active. See Is().
func (*Machine) IsClock ¶
IsClock checks if the machine has changed since the passed clock. Returns true if at least one state has changed.
func (*Machine) IsDisposed ¶ added in v0.8.0
IsDisposed returns true if the machine has been disposed.
func (*Machine) IsQueued ¶
func (m *Machine) IsQueued(mutationType MutationType, states S, withoutArgsOnly bool, statesStrictEqual bool, startIndex int, ) int
IsQueued checks if a particular mutation has been queued. Returns an index of the match or -1 if not found.
mutationType: add, remove, set
states: list of states used in the mutation
withoutParamsOnly: matches only mutation without the arguments object
statesStrictEqual: states of the mutation have to be exactly like `states` and not a superset.
func (*Machine) IsTime ¶ added in v0.7.0
IsTime checks if the machine has changed since the passed time (list of ticks). Returns true if at least one state has changed. The states param is optional and can be used to check only a subset of states.
func (*Machine) Log ¶
Log logs an [extern] message unless LogNothing is set (default). Optionally redirects to a custom logger from SetLogger.
func (*Machine) LogLvl ¶ added in v0.8.0
LogLvl adds an internal log entry from the outside. It should be used only by packages extending pkg/machine. Use Log instead.
func (*Machine) MustBindHandlers ¶ added in v0.8.0
MustBindHandlers is a panicking version of BindHandlers, useful in tests.
func (*Machine) MustParseStates ¶
MustParseStates parses the states and returns them as a list. Panics when a state is not defined. It's an usafe equivalent of VerifyStates.
func (*Machine) NewStateCtx ¶ added in v0.5.0
NewStateCtx returns a new sub-context, bound to the current clock's tick of the passed state.
Context cancels when the state has been de-activated, or right away, if it isn't currently active.
State contexts are used to check state expirations and should be checked often inside goroutines.
func (*Machine) Not ¶
Not checks if **none** of the passed states are currently active.
machine.StringAll() // -> ()[A:0 B:0 C:0 D:0] machine.Add(S{"A", "B"}) // not(A) and not(C) machine.Not(S{"A", "C"}) // -> false // not(C) and not(D) machine.Not(S{"C", "D"}) // -> true
func (*Machine) Not1 ¶ added in v0.5.0
Not1 is a shorthand method to check if a single state is currently inactive. See Not().
func (*Machine) PanicToErr ¶ added in v0.7.0
PanicToErr will catch a panic and add the Exception state. Needs to be called in a defer statement, just like a recover() call.
func (*Machine) PanicToErrState ¶ added in v0.7.0
PanicToErrState will catch a panic and add the Exception state, along with the passed state. Needs to be called in a defer statement, just like a recover() call.
func (*Machine) RegisterDisposalHandler ¶ added in v0.5.0
func (m *Machine) RegisterDisposalHandler(fn func())
RegisterDisposalHandler adds a function to be called when the machine is disposed. This function will block before mach.WhenDispose is closed.
func (*Machine) Remove ¶
Remove de-activates a list of states in the machine, returning the result of the transition (Executed, Queued, Canceled). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) Remove1 ¶ added in v0.5.0
Remove1 is a shorthand method to remove a single state with the passed args. See Remove().
func (*Machine) RemoveFromEv ¶ added in v0.5.0
RemoveFromEv TODO RemoveFromEv Planned.
func (*Machine) Resolver ¶
func (m *Machine) Resolver() RelationsResolver
Resolver return the relation resolver, used to produce target states of transitions.
func (*Machine) Set ¶
Set de-activates a list of states in the machine, returning the result of the transition (Executed, Queued, Canceled). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) SetLogArgs ¶ added in v0.5.0
func (m *Machine) SetLogArgs(mapper LogArgsMapper)
SetLogArgs accepts a function which decides which mutation arguments to log. See NewArgsMapper or create your own manually.
func (*Machine) SetLogId ¶ added in v0.8.0
SetLogId enables or disables the logging of the machine's id in log messages.
func (*Machine) SetLogLevel ¶
SetLogLevel sets the log level of the machine.
func (*Machine) SetLoggerEmpty ¶ added in v0.7.0
SetLoggerEmpty creates an empty logger that does nothing and sets the log level in one call. Useful when combined with am-dbg. Requires LogChanges log level to produce any output.
func (*Machine) SetLoggerSimple ¶ added in v0.7.0
SetLoggerSimple takes log.Printf and sets the log level in one call. Useful for testing. Requires LogChanges log level to produce any output.
func (*Machine) SetStruct ¶ added in v0.5.0
SetStruct sets the machine's state structure. It will automatically call VerifyStates with the names param and handle EventStructChange if successful. Note: it's not recommended to change the states structure of a machine which has already produced transitions.
func (*Machine) StateNames ¶
StateNames returns a copy of all the state names.
func (*Machine) StatesVerified ¶ added in v0.5.0
StatesVerified returns true if the state names have been ordered using VerifyStates.
func (*Machine) String ¶
String returns a one line representation of the currently active states, with their clock values. Inactive states are omitted. Eg: (Foo:1 Bar:3)
func (*Machine) StringAll ¶
StringAll returns a one line representation of all the states, with their clock values. Inactive states are in square brackets.
(Foo:1 Bar:3) [Baz:2]
func (*Machine) Switch ¶ added in v0.3.0
Switch returns the first state from the passed list that is currently active, making it handy for switch statements. Useful for state groups.
switch mach.Switch(ss.GroupPlaying) { case "Playing": case "Paused": case "Stopped": }
func (*Machine) Time ¶
Time returns machine's time, a list of ticks per state. Returned value includes the specified states, or all the states if nil.
func (*Machine) TimeSum ¶
TimeSum returns the sum of machine's time (ticks per state). Returned value includes the specified states, or all the states if nil. It's a very inaccurate, yet simple way to measure the machine's time. TODO handle overflow
func (*Machine) Toggle1 ¶ added in v0.8.0
Toggle1 activates or de-activates a single state, depending on its current state. Returns the result of the transition (Executed, Queued, Canceled).
func (*Machine) Transition ¶
func (m *Machine) Transition() *Transition
Transition returns the current transition, if any.
func (*Machine) VerifyStates ¶ added in v0.3.0
VerifyStates verifies an array of state names and returns an error in case at least one isn't defined. It also retains the order and uses it for StateNames. Verification can be checked via Machine.StatesVerified. Not thread-safe.
func (*Machine) When ¶
When returns a channel that will be closed when all the passed states become active or the machine gets disposed.
ctx: optional context that will close the channel when done. Useful when listening on 2 When() channels within the same `select` to GC the 2nd one. Allocates a new goroutine.
func (*Machine) WhenArgs ¶ added in v0.5.0
WhenArgs returns a channel that will be closed when the passed state becomes active with all the passed args. Args are compared using the native '=='. It's meant to be used with async Multi states, to filter out a specific completion.
func (*Machine) WhenDisposed ¶ added in v0.5.0
func (m *Machine) WhenDisposed() <-chan struct{}
WhenDisposed returns a channel that will be closed when the machine is disposed. Requires bound handlers. Use Machine.Disposed in case no handlers have been bound.
func (*Machine) WhenErr ¶
WhenErr returns a channel that will be closed when the machine is in the Exception state.
ctx: optional context defaults to the machine's context.
func (*Machine) WhenNot ¶
WhenNot returns a channel that will be closed when all the passed states become inactive or the machine gets disposed.
ctx: optional context that will close the channel when done. Useful when listening on 2 WhenNot() channels within the same `select` to GC the 2nd one.
func (*Machine) WhenNot1 ¶ added in v0.5.0
WhenNot1 is an alias to WhenNot() for a single state. See WhenNot.
func (*Machine) WhenQueueEnds ¶ added in v0.5.0
WhenQueueEnds closes every time the queue ends, or the optional ctx expires.
func (*Machine) WhenTicks ¶ added in v0.5.0
WhenTicks waits N ticks of a single state (relative to now). Uses WhenTime underneath.
func (*Machine) WhenTicksEq ¶ added in v0.5.0
WhenTicksEq waits till ticks for a single state equal the given value (or more). Uses WhenTime underneath.
func (*Machine) WhenTime ¶ added in v0.5.0
WhenTime returns a channel that will be closed when all the passed states have passed the specified time. The time is a logical clock of the state. Machine time can be sourced from the Time() method, or Clock() for a specific state.
func (*Machine) WillBe ¶ added in v0.8.0
WillBe returns true if the passed states are scheduled to be activated. See IsQueued to perform more detailed queries.
func (*Machine) WillBe1 ¶ added in v0.8.0
WillBe1 returns true if the passed state is scheduled to be activated. See IsQueued to perform more detailed queries.
func (*Machine) WillBeRemoved ¶ added in v0.8.0
WillBeRemoved returns true if the passed states are scheduled to be de-activated. See IsQueued to perform more detailed queries.
func (*Machine) WillBeRemoved1 ¶ added in v0.8.0
WillBeRemoved1 returns true if the passed state is scheduled to be de-activated. See IsQueued to perform more detailed queries.
type Mutation ¶
type Mutation struct { // add, set, remove Type MutationType // states explicitly passed to the mutation method // TODO optimize as index-based CalledStates() S CalledStates S // argument map passed to the mutation method (if any). Args A // this mutation has been triggered by an auto state Auto bool // contains filtered or unexported fields }
Mutation represents an atomic change (or an attempt) of machine's active states. Mutation causes a Transition.
func (Mutation) StateWasCalled ¶ added in v0.5.0
StateWasCalled returns true if the Mutation was called (directly) with the passed state (in opposite to it coming from an `Add` relation). TODO change to CalledIs(), CalledIs1(), CalledAny(), CalledAny1()
type MutationType ¶
type MutationType int
MutationType enum
const ( MutationAdd MutationType = iota MutationRemove MutationSet )
func (MutationType) String ¶
func (m MutationType) String() string
type NoOpTracer ¶ added in v0.6.0
type NoOpTracer struct{}
NoOpTracer is a no-op implementation of Tracer, used for embedding.
func (*NoOpTracer) HandlerEnd ¶ added in v0.6.0
func (t *NoOpTracer) HandlerEnd( transition *Transition, emitter string, handler string)
func (*NoOpTracer) HandlerStart ¶ added in v0.6.0
func (t *NoOpTracer) HandlerStart( transition *Transition, emitter string, handler string)
func (*NoOpTracer) Inheritable ¶ added in v0.6.0
func (t *NoOpTracer) Inheritable() bool
func (*NoOpTracer) MachineDispose ¶ added in v0.6.0
func (t *NoOpTracer) MachineDispose(machID string)
func (*NoOpTracer) MachineInit ¶ added in v0.6.0
func (t *NoOpTracer) MachineInit(machine Api) context.Context
func (*NoOpTracer) NewSubmachine ¶ added in v0.6.0
func (t *NoOpTracer) NewSubmachine(parent, machine Api)
func (*NoOpTracer) QueueEnd ¶ added in v0.6.0
func (t *NoOpTracer) QueueEnd(machine Api)
func (*NoOpTracer) StructChange ¶ added in v0.7.0
func (t *NoOpTracer) StructChange(machine Api, old Struct)
func (*NoOpTracer) TransitionEnd ¶ added in v0.6.0
func (t *NoOpTracer) TransitionEnd(transition *Transition)
func (*NoOpTracer) TransitionInit ¶ added in v0.6.0
func (t *NoOpTracer) TransitionInit(transition *Transition)
func (*NoOpTracer) TransitionStart ¶ added in v0.7.0
func (t *NoOpTracer) TransitionStart(transition *Transition)
func (*NoOpTracer) VerifyStates ¶ added in v0.7.0
func (t *NoOpTracer) VerifyStates(machine Api)
type Opts ¶
type Opts struct { // Unique ID of this machine. Default: random ID. ID string // Time for a handler to execute. Default: time.Second HandlerTimeout time.Duration // If true, the machine will NOT print all exceptions to stdout. DontLogStackTrace bool // If true, the machine will die on panics. DontPanicToException bool // If true, the machine will NOT prefix its logs with its ID. DontLogID bool // Custom relations resolver. Default: *DefaultRelationsResolver. Resolver RelationsResolver // Log level of the machine. Default: LogNothing. LogLevel LogLevel // Tracer for the machine. Default: nil. Tracers []Tracer // LogArgs matching function for the machine. Default: nil. LogArgs func(args A) map[string]string // Parent machine, used to inherit certain properties, e.g. tracers. // Overrides ParentID. Default: nil. Parent Api // ParentID is the ID of the parent machine. Default: "". ParentID string // Tags is a list of tags for the machine. Default: nil. Tags []string // QueueLimit is the maximum number of mutations that can be queued. // Default: 1000. // TODO per-state QueueLimit QueueLimit int // DetectEval will detect Eval calls directly in handlers, which causes a // deadlock. It works in similar way as -race flag in Go and can also be // triggered by setting either env var: AM_DEBUG=1 or AM_DETECT_EVAL=1. // Default: false. DetectEval bool }
Opts struct is used to configure a new Machine.
func OptsWithDebug ¶ added in v0.5.0
OptsWithDebug returns Opts with debug settings (DontPanicToException, long HandlerTimeout).
func OptsWithTracers ¶ added in v0.5.0
OptsWithTracers returns Opts with the given tracers. Tracers are inherited by submachines (via Opts.Parent) when env.AM_DEBUG is set.
type RelationsResolver ¶
type RelationsResolver interface { // GetTargetStates returns the target states after parsing the relations. GetTargetStates(t *Transition, calledStates S) S // GetAutoMutation returns an (optional) auto mutation which is appended to // the queue after the transition is executed. GetAutoMutation() *Mutation // SortStates sorts the states in the order their handlers should be // executed. SortStates(states S) // GetRelationsOf returns a list of relation types of the given state. GetRelationsOf(fromState string) ([]Relation, error) // GetRelationsBetween returns a list of relation types between the given // states. GetRelationsBetween(fromState, toState string) ([]Relation, error) // NewStruct runs when Machine receives a new struct. NewStruct() }
RelationsResolver is an interface for parsing relations between states. Not thread-safe. TODO support custom relation types and additional state properties.
type Result ¶
type Result int
Result enum is the result of a state Transition.
const ( // Executed means that the transition was executed immediately and not // canceled. Executed Result = 1 << iota // Canceled means that the transition was canceled, by either relations or a // handler. Canceled // Queued means that the transition was queued for later execution. The // following methods can be used to wait for the results: // - Machine.When // - Machine.WhenNot // - Machine.WhenArgs // - Machine.WhenTime // - Machine.WhenTicks // - Machine.WhenTicksEq Queued // ResultNoOp means that the transition was a no-op, i.e. the state was // already active. ResultNoOp is only used by helpers, and never returned by // the machine itself. ResultNoOp )
type S ¶
type S []string
S (state names) is a string list of state names.
func DiffStates ¶
DiffStates returns the states that are in states1 but not in states2.
type Serialized ¶ added in v0.7.0
type Serialized struct { // ID is the ID of a state machine. ID string `json:"id" yaml:"id"` // Time represents machine time - a list of state activation counters. Time Time `json:"time" yaml:"time"` // StateNames is an ordered list of state names. StateNames S `json:"state_names" yaml:"state_names" toml:"state_names"` }
Serialized is a machine state serialized to a JSON/YAML/TOML compatible struct. One also needs the state Struct to re-create a state machine.
type State ¶
State defines a single state of a machine, its properties and relations.
type StatesBase ¶ added in v0.8.0
type StatesBase struct { // Exception is the only built-in state and mean a global error. All errors // have to [State.Require] the Exception state. If [Machine.PanicToErr] is // true, Exception will receive it. Exception string // contains filtered or unexported fields }
func (*StatesBase) Names ¶ added in v0.8.0
func (b *StatesBase) Names() S
func (*StatesBase) SetNames ¶ added in v0.8.0
func (b *StatesBase) SetNames(names S)
type Step ¶ added in v0.5.0
type Step struct { Type StepType // optional, unless no ToState // TODO optimize as index-based FromState() S FromState string // optional, unless no FromState // TODO optimize as index-based ToState() S ToState string // eg a transition method name, relation type Data any // marks a final handler (FooState, FooEnd) IsFinal bool // marks a self handler (FooFoo) IsSelf bool // marks an enter handler (FooEnter). Requires IsFinal. IsEnter bool }
Step struct represents a single step within a Transition, either a relation resolving step or a handler call.
type Struct ¶ added in v0.5.0
Struct is a map of state names to state definitions.
func CloneStates ¶ added in v0.5.0
CloneStates deep clones the states struct and returns a copy.
func StructMerge ¶ added in v0.7.0
StructMerge merges multiple state structs into one, overriding the previous state definitions. No relation-level merging takes place.
type Time ¶ added in v0.7.0
type Time []uint64
Time is machine time, an ordered list of state ticks. It's like Clock, but indexed by int, instead of string. TODO use math/big?
func (Time) Is ¶ added in v0.7.0
Is checks if all the passed states were active at a given time, via indexes. See Machine.Index().
type Tracer ¶ added in v0.5.0
type Tracer interface { TransitionInit(transition *Transition) TransitionStart(transition *Transition) TransitionEnd(transition *Transition) HandlerStart(transition *Transition, emitter string, handler string) HandlerEnd(transition *Transition, emitter string, handler string) // MachineInit is called only for machines with tracers added via // Opts.Tracers. MachineInit(machine Api) context.Context MachineDispose(machID string) NewSubmachine(parent, machine Api) Inheritable() bool QueueEnd(machine Api) StructChange(machine Api, old Struct) VerifyStates(machine Api) }
Tracer is an interface for logging machine transitions and events, used by Opts.Tracers and Machine.BindTracer.
type Transition ¶
type Transition struct { // ID is a unique identifier of the transition. ID string // Steps is a list of steps taken by this transition (so far). Steps []*Step // TimeBefore is the machine time from before the transition. TimeBefore Time // TimeAfter is the machine time from after the transition. If the transition // has been canceled, this will be the same as TimeBefore. TimeAfter Time // TargetIndexes is a list of indexes of the target states. TargetIndexes []int // Enters is a list of states with enter handlers in this transition. Enters S // Enters is a list of states with exit handlers in this transition. Exits S // Accepted tells if the transition was accepted during the negotiation phase. Accepted bool // Mutation call which caused this transition Mutation *Mutation // Machine is the parent machine of this transition. Machine *Machine // Api is a subset of Machine. // TODO call when applicable instead of calling Machine Api Api // LogEntries are log msgs produced during the transition. LogEntries []*LogEntry // PreLogEntries are log msgs produced before during the transition. PreLogEntries []*LogEntry // QueueLen is the length of the queue after the transition. QueueLen int // LogEntriesLock is used to lock the logs to be collected by a Tracer. LogEntriesLock sync.Mutex // contains filtered or unexported fields }
Transition represents processing of a single mutation within a machine.
func (*Transition) Args ¶
func (t *Transition) Args() A
Args returns the argument map passed to the mutation method (or an empty one).
func (*Transition) CalledStates ¶
func (t *Transition) CalledStates() S
CalledStates return explicitly called / requested states of the transition.
func (*Transition) ClockAfter ¶ added in v0.7.0
func (t *Transition) ClockAfter() Clock
ClockAfter return the Clock from before the transition.
func (*Transition) ClockBefore ¶ added in v0.7.0
func (t *Transition) ClockBefore() Clock
ClockBefore return the Clock from before the transition.
func (*Transition) IsAuto ¶
func (t *Transition) IsAuto() bool
IsAuto returns true if the transition was triggered by an auto state. Thus, it cant trigger any other auto state mutations.
func (*Transition) IsCompleted ¶
func (t *Transition) IsCompleted() bool
func (*Transition) LogArgs ¶ added in v0.5.0
func (t *Transition) LogArgs() string
LogArgs returns a text snippet with arguments which should be logged for this Mutation.
func (*Transition) StatesBefore ¶
func (t *Transition) StatesBefore() S
StatesBefore is a list of states before the transition.
func (*Transition) String ¶
func (t *Transition) String() string
String representation of the transition and the steps taken so far.
func (*Transition) TargetStates ¶
func (t *Transition) TargetStates() S
TargetStates is a list of states after parsing the relations.
func (*Transition) Type ¶
func (t *Transition) Type() MutationType
Type returns the type of the mutation (add, remove, set).
type WhenArgsBinding ¶ added in v0.7.0
type WhenArgsBinding struct {
// contains filtered or unexported fields
}
type WhenBinding ¶ added in v0.7.0
type WhenBinding struct { Ch chan struct{} // means states are required to NOT be active Negation bool States StateIsActive Matched int Total int }
type WhenTimeBinding ¶ added in v0.7.0
type WhenTimeBinding struct { Ch chan struct{} // map of completed to their index positions // TODO optimize indexes Index map[string]int // number of matches so far Matched int // number of total matches needed Total int // optional Time to match for completed from Index Times Time Completed StateIsActive }