diff --git a/pkg/machine/machine.go b/pkg/machine/machine.go index 1b6fa2f..bc479a4 100644 --- a/pkg/machine/machine.go +++ b/pkg/machine/machine.go @@ -85,11 +85,19 @@ type Machine struct { // New creates a new Machine instance, bound to context and modified with // optional Opts -func New(ctx context.Context, states States, opts *Opts) *Machine { +func New(ctx context.Context, states States, opts *Opts) *Machine { // parse relations + parsedStates := cloneStates(states) + for name, state := range states { + // avoid self removal + if lo.Contains(state.Remove, name) { + state.Remove = lo.Without(state.Remove, name) + parsedStates[name] = state + } + } m := &Machine{ ID: uuid.New().String(), HandlerTimeout: time.Second, - States: states, + States: parsedStates, clock: map[string]uint64{}, emitters: []*emitter{}, PrintExceptions: true, diff --git a/pkg/machine/misc.go b/pkg/machine/misc.go index 88a880c..4491ce1 100644 --- a/pkg/machine/misc.go +++ b/pkg/machine/misc.go @@ -322,3 +322,32 @@ func padString(str string, length int, pad string) string { } } } + +// cloneStates deep clones the states struct and returns a copy. +func cloneStates(states States) States { + ret := make(States) + for name, state := range states { + stateCopy := State{ + Auto: state.Auto, + Multi: state.Multi, + } + if state.Require != nil { + stateCopy.Require = make(S, len(state.Require)) + copy(stateCopy.Require, state.Require) + } + if state.Add != nil { + stateCopy.Add = make(S, len(state.Add)) + copy(stateCopy.Add, state.Add) + } + if state.Remove != nil { + stateCopy.Remove = make(S, len(state.Remove)) + copy(stateCopy.Remove, state.Remove) + } + if state.After != nil { + stateCopy.After = make(S, len(state.After)) + copy(stateCopy.After, state.After) + } + ret[name] = stateCopy + } + return ret +}