using System; namespace imm; public record class Context : imm.Recorded { } public record class State( CTX Context ) : imm.Recorded> where T : State where CTX : Context { virtual public (CTX, T) onEnter(CTX ctx, State oldState) { return (ctx, (T)this); } virtual public (CTX, T) onExit(CTX ctx, State newState) { return (ctx, (T)this); } } public record class FSM : imm.Recorded> where T : FSM where ST : State where CTX : Context { public CTX Context { get; init; } public ST State { get; init; } public FSM( CTX context, ST stStart ) { Context = context; State = stStart; } public FSM Transition(ST newState) { var origState = State; var (newOldCTX, oldState) = State.onExit(Context, newState); var (newCTX, storeState) = newState.onEnter(newOldCTX, oldState); var newFSM = this.Process( this with { Context = newCTX, State = storeState, }, $"Trans: {origState.GetType().Name} to {newState.GetType().Name}" ); return newFSM; } public FSM Process( Func fn, string reason ) { var newState = fn( State ); if( object.ReferenceEquals( newState, State ) ) return this; FSM newFSM = this.Process( this with { Context = Context, State = newState, }, $"Processing: {newState.GetType().Name} for {reason}" ); return newFSM; } }