wip async state machine event processing

This commit is contained in:
Ben Bierens 2023-02-08 15:29:07 +01:00 committed by Mark Spanbroek
parent 894cbe4a0b
commit 4cf982e327
No known key found for this signature in database
GPG Key ID: FBE3E9548D427C00
2 changed files with 46 additions and 28 deletions

View File

@ -3,15 +3,21 @@ import pkg/chronos
type
AsyncStateMachine* = ref object of RootObj
state: AsyncState
AsyncState* = ref object of RootObj
Event* = proc(state: AsyncState): ?AsyncState
method run*(state: AsyncState): Future[?AsyncState] {.base.} =
discard
proc runState(state: AsyncState): Future[void] {.async.} =
proc runState(machine: AsyncStateMachine, state: AsyncState): Future[void] {.async.} =
machine.state = state
if next =? await state.run():
await runState(next)
await machine.runState(next)
proc start*(stateMachine: AsyncStateMachine, initialState: AsyncState) =
asyncSpawn runState(initialState)
asyncSpawn stateMachine.runState(initialState)
proc schedule*(stateMachine: AsyncStateMachine, event: Event) =
if next =? stateMachine.state.event():
asyncSpawn stateMachine.runState(next)

View File

@ -5,45 +5,57 @@ import codex/utils/asyncstatemachine
import ../helpers/eventually
type
TestState = ref object of AsyncState
State1 = ref object of AsyncState
State2 = ref object of AsyncState
AsyncTestState = ref object of AsyncState
State1 = ref object of AsyncTestState
State2 = ref object of AsyncTestState
State3 = ref object of AsyncTestState
var runInvoked = 0
var state1runInvoked = 0
var state2runInvoked = 0
var state3runInvoked = 0
method run(state: TestState): Future[?AsyncState] {.async.} =
inc runInvoked
method onMoveToNextStateEvent*(state: AsyncTestState): ?AsyncState {.base.} =
discard
method run(state: State1): Future[?AsyncState] {.async.} =
inc state1runInvoked
return some AsyncState(State2.new())
method run(state: State2): Future[?AsyncState] {.async.} =
inc state2runInvoked
suite "async state machines":
setup:
runInvoked = 0
state2runInvoked = 0
method onMoveToNextStateEvent(state: State2): ?AsyncState =
return some AsyncState(State3.new())
test "creates async state machine":
let sm = AsyncStateMachine.new()
check sm != nil
method run(state: State3): Future[?AsyncState] {.async.} =
inc state3runInvoked
suite "async state machines":
var machine: AsyncStateMachine
var state1, state2: AsyncState
setup:
state1runInvoked = 0
state2runInvoked = 0
state3runInvoked = 0
machine = AsyncStateMachine.new()
state1 = State1.new()
state2 = State2.new()
test "should call run on start state":
let sm = AsyncStateMachine.new()
let testState = TestState.new()
sm.start(testState)
check eventually runInvoked == 1
machine.start(state1)
check eventually state1runInvoked == 1
test "moves to next state when run completes":
let sm = AsyncStateMachine.new()
let state1 = State1.new()
let state2 = State2.new()
sm.start(state1)
machine.start(state1)
check eventually state2runInvoked == 1
test "state2 moves to state3 on event":
machine.start(state2)
proc moveToNextStateEvent(state: AsyncState): ?AsyncState =
AsyncTestState(state).onMoveToNextStateEvent()
machine.schedule(Event(moveToNextStateEvent))
check eventually state3runInvoked == 1