stateful

package module
v0.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2020 License: MIT Imports: 4 Imported by: 2

README ΒΆ

Welcome to stateful πŸ‘‹

Travis CI

Create easy state machines with your existing code

Table of Contents

  1. Documentation
  2. Usage
  3. Draw graph
  4. Wildcards
  5. Examples
  6. Credits

Documentation

You can find the documentation here: https://pkg.go.dev/github.com/bykof/stateful?tab=doc

Usage

It is very easy to use stateful. Just create a struct and implement the stateful interface

import "github.com/bykof/stateful"

type (
    MyMachine struct {
        state   stateful.State
        amount  int
    }
	
    AmountParams struct {
        Amount  int
    }
)

func NewMyMachine() MyMachine {
    return MyMachine{
        state:  A,
        amount: 0,
    }
}

// State implement interface stateful 
func (mm MyMachine) State() stateful.State {
    return mm.state
}

//  SetState implement interface stateful
func (mm *MyMachine) SetState(state stateful.State) error {
    mm.state = state
    return nil
}

Declare some proper states:

const (
    A = stateful.DefaultState("A")
    B = stateful.DefaultState("B")
)

Then add some transitions to the machine:

// Declare a transition of you machine and return the new state of the machine. 
func (mm *MyMachine) FromAToB(transitionArguments stateful.TransitionArguments) (stateful.State, error) {
    amountParams, ok := transitionArguments.(AmountParams)
    if !ok {
        return nil, errors.New("could not parse AmountParams")
    }
	
    mm.amount += amountParams.Amount
    return B, nil
} 

func (mm *MyMachine) FromBToA(transitionArguments stateful.TransitionArguments) (stateful.State, error) {
    amountParams, ok := transitionArguments.(AmountParams)
    if !ok {
        return nil, errors.New("could not parse AmountParams")
    }
	
    mm.amount -= amountParams.Amount
    return A, nil
}

// The state machine will check, if you transfer to a proper and defined state in the machine. See below. 
func (mm *MyMachine) FromAToNotExistingC(_ stateful.TransitionArguments) (stateful.State, error) {
	return stateful.DefaultState("C")
}

And now initialize the machine:

myMachine := NewMyMachine()
stateMachine := &stateful.StateMachine{
    StatefulObject: &myMachine,
}

stateMachine.AddTransition(
    // The transition function 
    myMachine.FromAToB,
    // SourceStates
    stateful.States{A},
    // DestinationStates
    stateful.States{B},
)

stateMachine.AddTransition(
    myMachine.FromBToA,
    stateful.States{B},
    stateful.States{A},
)

Everything is done! Now run the machine:

_ := stateMachine.Run(
    // The transition function
    myMachine.FromAToB, 
    // The transition params which will be passed to the transition function
    stateful.TransitionArguments(AmountParams{Amount: 1}),
)

_ = stateMachine.Run(
    myMachine.FromBToA, 
    stateful.TransitionArguments(AmountParams{Amount: 1}),
)

err := stateMachine.Run(
   myMachine.FromBToA, 
   stateful.TransitionArguments(AmountParams{Amount: 1}),
)

// We cannot run the transition "FromBToA" from current state "A"... 
if err != nil {
    log.Fatal(err) // will print: you cannot run FromAToB from state A
}

// We cannot transfer the machine with current transition to returned state "C"
err = stateMachine.Run(
    myMachine.FromAToNotExistingC, 
    stateful.TransitionArguments(nil),
)

if err != nil {
    log.Fatal(err) // will print: you cannot transfer to state C 
}

That's it!

Draw graph

You can draw a graph of your state machine in dot format of graphviz.

Just pass in your created statemachine into the StateMachineGraph.

import "github.com/bykof/stateful/src/statefulGraph"
stateMachineGraph := statefulGraph.StateMachineGraph{StateMachine: *stateMachine}
_ = stateMachineGraph.DrawGraph()

This will print following to the console:

digraph  {
	A->B[ label="FromAToB" ];
	B->A[ label="FromBToA" ];
	A;
	B;
	
}

which is actually this graph:

MyMachine Transition Graph

Wildcards

You can also address wildcards as SourceStates or DestinationStates

stateMachine.AddTransition(
    myMachine.FromBToAllStates,
    stateful.States{B},
    stateful.States{stateful.AllStates},
)

This will give you the opportunity to jump e.g. B to AllStates.

Keep in mind that AllStates creates a lot of complexity and maybe a missbehavior. So use it only if you are knowing what you are doing

Examples

Have a look at the examples: examples

Credits

Thank you calhoun for the sweet gopher image!

Run tests

go test ./...

Author

πŸ‘€ Michael Bykovski

Show your support

Give a ⭐️ if this project helped you!

πŸ“ License

Copyright Β© 2019 Michael Bykovski.
This project is MIT licensed.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

View Source
const (
	// AllStates is a wildcard which represents all states in the state machine
	AllStates = DefaultState("*")
)

Variables ΒΆ

This section is empty.

Functions ΒΆ

This section is empty.

Types ΒΆ

type CannotRunFromStateError ΒΆ

type CannotRunFromStateError struct {
	// contains filtered or unexported fields
}

func NewCannotRunFromStateError ΒΆ

func NewCannotRunFromStateError(stateMachine StateMachine, transitionRule TransitionRule) *CannotRunFromStateError

func (CannotRunFromStateError) Error ΒΆ

func (crfse CannotRunFromStateError) Error() string

type CannotTransferToStateError ΒΆ

type CannotTransferToStateError struct {
	// contains filtered or unexported fields
}

func NewCannotTransferToStateError ΒΆ

func NewCannotTransferToStateError(state State) *CannotTransferToStateError

func (CannotTransferToStateError) Error ΒΆ

func (cttse CannotTransferToStateError) Error() string

type DefaultState ΒΆ

type DefaultState string

DefaultState is a string which should be used in every stateful object as the state

func (DefaultState) GetID ΒΆ

func (ds DefaultState) GetID() string

GetID returns the string representation of the DefaultState

func (DefaultState) IsWildCard ΒΆ

func (ds DefaultState) IsWildCard() bool

IsWildCard checks if the current state is a wildcard. So if the state stands for all possible states

type State ΒΆ

type State interface {
	GetID() string
	IsWildCard() bool
}

State represents a state of a stateful object

type StateMachine ΒΆ

type StateMachine struct {
	StatefulObject Stateful
	// contains filtered or unexported fields
}

StateMachine handles the state of the StatefulObject

func (*StateMachine) AddTransition ΒΆ

func (sm *StateMachine) AddTransition(
	transition Transition,
	sourceStates States,
	destinationStates States,
)

AddTransition adds a transition to the state machine.

func (StateMachine) GetAllStates ΒΆ

func (sm StateMachine) GetAllStates() States

GetAllStates returns all known and possible states by the state machine

func (StateMachine) GetAvailableTransitions ΒΆ

func (sm StateMachine) GetAvailableTransitions() Transitions

func (StateMachine) GetTransitionRules ΒΆ

func (sm StateMachine) GetTransitionRules() TransitionRules

GetTransitionRules returns all transitionRules in the state machine

func (StateMachine) Run ΒΆ

func (sm StateMachine) Run(
	transition Transition,
	transitionArguments TransitionArguments,
) error

Run runs the state machine with the given transition. If the transition

type Stateful ΒΆ

type Stateful interface {
	// State returns the current state of the stateful object
	State() State

	// SetState sets the state of the stateful object and returns an error if it fails
	SetState(state State) error
}

Stateful is the core interface which should be implemented by all stateful structs. If this interface is implemented by a struct it can be processed by the state machine

type States ΒΆ

type States []State

States are a slice of State

func (States) Contains ΒΆ

func (ss States) Contains(state State) bool

Contains search in States if the given state is inside the States. It compares with GetID

func (States) HasWildCard ΒΆ

func (ss States) HasWildCard() bool

HasWildCard checks if there is a wildcard state inside of States

type Transition ΒΆ

type Transition func(transitionArguments TransitionArguments) (State, error)

Transition represents the transition function which will be executed if the order is in the proper state and there is a valid transitionRule in the state machine

func (Transition) GetID ΒΆ

func (t Transition) GetID() uintptr

func (Transition) GetName ΒΆ

func (t Transition) GetName() string

type TransitionArguments ΒΆ added in v0.0.7

type TransitionArguments interface{}

TransitionArguments represents the arguments

type TransitionRule ΒΆ

type TransitionRule struct {
	SourceStates      States
	Transition        Transition
	DestinationStates States
}

func (TransitionRule) IsAllowedToRun ΒΆ

func (tr TransitionRule) IsAllowedToRun(state State) bool

func (TransitionRule) IsAllowedToTransfer ΒΆ

func (tr TransitionRule) IsAllowedToTransfer(state State) bool

type TransitionRuleNotFoundError ΒΆ

type TransitionRuleNotFoundError struct {
	// contains filtered or unexported fields
}

func NewTransitionRuleNotFoundError ΒΆ

func NewTransitionRuleNotFoundError(transition Transition) *TransitionRuleNotFoundError

func (TransitionRuleNotFoundError) Error ΒΆ

func (trnfe TransitionRuleNotFoundError) Error() string

type TransitionRules ΒΆ

type TransitionRules []TransitionRule

func (TransitionRules) Find ΒΆ

func (trs TransitionRules) Find(transition Transition) *TransitionRule

type Transitions ΒΆ

type Transitions []Transition

Transitions are a slice of Transition

func (Transitions) Contains ΒΆ

func (ts Transitions) Contains(transition Transition) bool

Directories ΒΆ

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL