fsmgen

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 30, 2021 License: MIT Imports: 6 Imported by: 0

README

go-fsmgen

Documentation Go Report Card GitHub issues license

go-fsmgen is a Finite State Machine generator. It provides a strongly typed implementation of a FSM through code generation.

go get github.com/snikch/go-fsmgen

Generation

For a full example, see the examples directory.

func main() {
	gen := fsmgen.New("audio_player", AudioPlayerState{}, AudioPlayerEnvironment{}, "init", "loading", "playing", "paused")
	gen.PackageName = "main"
	gen.AddEvent(fsmgen.NewEvent("load", EventLoad{}).FromAny().To("loading"))
	gen.AddEvent(fsmgen.NewEvent("play", EventPlay{}).From("paused", "loading").To("playing"))
	gen.AddEvent(fsmgen.NewEvent("pause", EventPause{}).From("playing").To("paused"))
	gen.AddEvent(fsmgen.NewEvent("error", EventError{}).FromAny().To("init"))
	err := gen.Write()
	if err != nil {
		log.Panic(err)
	}
}

Usage

func main() {
	ctx := context.Background()
	machine := NewMachine()
	err := machine.TriggerLoad(ctx, EventLoad{
		File: nil,
	})
	if err != nil {
		log.Panic(err)
	}
	time.Sleep(2 * time.Second)
	err = machine.TriggerPause(ctx, EventPause{})
	if err != nil {
		log.Panic(err)
	}
	err = machine.TriggerPause(ctx, EventPause{})
	if err != nil {
		log.Print("error: " + err.Error())
	}
}

func NewMachine() *AudioPlayerMachine {
	env := AudioPlayerEnvironment{Logger: log.New(os.Stdout, "fsm ", 0)}
	machine := NewAudioPlayerMachine(&AudioPlayerState{
		Player: &StringAudioPlayer{},
	}, env)
	machine.LoadAction = func(ctx AudioPlayerMachineContext, state *AudioPlayerState, ev EventLoad) error {
		state.file = ev.File
		return nil
	}
	machine.ErrorAction = func(ctx AudioPlayerMachineContext, state *AudioPlayerState, ev EventError) error {
		state.Message = ev.Message
		return nil
	}
	machine.OnStateLoading = func(ctx AudioPlayerMachineContext, env AudioPlayerEnvironment, state AudioPlayerState) error {
		env.Logger.Print("Did enter State Loading")
		err := state.Player.Load(state.file)
		if err != nil {
			return ctx.TriggerError(EventError{
				Message: err.Error(),
			})
		}
		return ctx.TriggerPlay(EventPlay{})
	}
	machine.OnStatePlaying = func(ctx AudioPlayerMachineContext, env AudioPlayerEnvironment, state AudioPlayerState) error {
		env.Logger.Print("Did enter State Playing")
		err := state.Player.Play()
		if err != nil {
			return ctx.TriggerError(EventError{
				Message: err.Error(),
			})
		}
		return nil
	}
	machine.OnStatePaused = func(ctx AudioPlayerMachineContext, env AudioPlayerEnvironment, state AudioPlayerState) error {
		env.Logger.Print("Did enter State Paused")
		err := state.Player.Pause()
		if err != nil {
			return ctx.TriggerError(EventError{
				Message: err.Error(),
			})
		}
		return nil
	}
	return machine
}
$ ./audioplayer
fsm Did enter State Loading
2020/11/13 06:35:38 Loading
fsm Did enter State Playing
2020/11/13 06:35:38 Play
fsm Did enter State Paused
2020/11/13 06:35:40 Pause
2020/11/13 06:35:40 error: invalid transition: no transition target from paused via pause

See Also

Design influenced by the following projects:

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	Name       string
	FromStates []string
	ToState    string
	ObjName    reflect.Type
}

Event defines an Event that transitions from a set of states to a new state.

func NewEvent

func NewEvent(name string, obj interface{}) *Event

NewEvent returns a new event with the supplied name and Event object.

func (*Event) From

func (ev *Event) From(from ...string) *Event

From defines the states that are valid as source states for this event.

func (*Event) FromAny

func (ev *Event) FromAny() *Event

FromAny defines all states as valid source states for this event.

func (*Event) To

func (ev *Event) To(to string) *Event

To defines the target state after this event.

type Generator

type Generator struct {
	// Name is the name of the state machine. It defines the name of the types and file generated.
	Name string
	// PackageName defines the name of the package the generated file belongs to. Defaults to Name.
	PackageName string
	// Filename defines where the state machine file will be written to. Defaults to Name.generated.go
	Filename string
	// States contains all of the state names that the state machine may be in.
	States []string
	// Events is a slice of all possible events that can occur in the state machine.
	Events []*Event
	// contains filtered or unexported fields
}

Generator provides a type for defining a finite state machine's states and events.

func New

func New(name string, stateObj interface{}, envObj interface{}, states ...string) *Generator

New returns a new Generator with the supplied name, types and states. The first supplied state is the initial state. The stateObj and envObj values can be either a struct, pointer to a struct or a string naming a type. Unfortunately you cannot pass an interface, so if this is required simply pass in the interface's name as a string.

func (*Generator) AddEvent

func (gen *Generator) AddEvent(ev *Event)

AddEvent adds the supplied event to the generated state machine.

func (*Generator) Write

func (gen *Generator) Write() error

Write will generator and output the state machine to file.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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