using System; using System.Runtime.CompilerServices; using Optional; namespace imm; public record class Context : imm.Recorded { } public record class State( CTX Context ) : imm.Recorded where TSUB : State where CTX : Context { virtual public (CTX, TSUB) onEnter(CTX ctx, State oldState) { return (ctx, (TSUB)this); } virtual public (CTX, TSUB) onExit(CTX ctx, State newState) { return (ctx, (TSUB)this); } } public record class FSM : imm.Recorded where TSUB : 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 TSUB Transition(ST newState, string reason, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, [CallerArgumentExpression("fn")] string expression = default ) { log.debug( $"Trans from {State.GetType().Name} to {newState.GetType().Name} for {reason}" ); var origState = State; var (newCtx, oldState) = State.onExit(Context, newState); var (newCTX, storeState) = newState.onEnter(newCtx, oldState); var newFSM = this.Process( (v) => (this as TSUB) with { Context = newCTX, State = storeState, }, $"{reason}" ); return newFSM; } /* public TSUB ( Func fn, string reason, [CallerMemberName] string member = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0, [CallerArgumentExpression("fn")] string expression = default ) { var newState = fn( State ); if( object.ReferenceEquals( newState, State ) ) return (TSUB)this; TSUB newFSM = this.Process( this with { Context = Context, State = newState, }, $"Processing: {newState.GetType().Name} for {reason}", member, file, line, expression ); return (TSUB)newFSM; } */ }