sharplib/imm/FSM.cs

81 lines
1.5 KiB
C#

using System;
namespace imm;
public record class Context : imm.Recorded<Context>
{
}
public record class State<T, CTX>( CTX Context ) : imm.Recorded<State<T, CTX>>
where T : State<T, CTX>
where CTX : Context
{
virtual public (CTX, T) onEnter(CTX ctx, State<T, CTX> oldState)
{
return (ctx, (T)this);
}
virtual public (CTX, T) onExit(CTX ctx, State<T, CTX> newState)
{
return (ctx, (T)this);
}
}
public record class FSM<T, ST, CTX> : imm.Recorded<FSM<T, ST, CTX>>
where T : FSM<T, ST, CTX>
where ST : State<ST, CTX>
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<T, ST, CTX> 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<T, ST, CTX> Process( Func<ST, ST> fn, string reason )
{
var newState = fn( State );
if( object.ReferenceEquals( newState, State ) ) return this;
FSM<T, ST, CTX> newFSM = this.Process( this with
{
Context = Context,
State = newState,
}, $"Processing: {newState.GetType().Name} for {reason}" );
return newFSM;
}
}