58 lines
2.7 KiB
Nim
58 lines
2.7 KiB
Nim
|
# nim-raft
|
||
|
# Copyright (c) 2023 Status Research & Development GmbH
|
||
|
# Licensed under either of
|
||
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||
|
# at your option.
|
||
|
# This file may not be copied, modified, or distributed except according to
|
||
|
# those terms.
|
||
|
|
||
|
import std/tables
|
||
|
import std/rlocks
|
||
|
|
||
|
type
|
||
|
# Define callback to use with Terminals
|
||
|
ConsensusFSMCallbackType*[NodeType] = proc(node: NodeType) {.gcsafe.}
|
||
|
# Define Non-Terminals as a (unique) tuples of the internal state and a sequence of callbacks
|
||
|
NonTerminalSymbol*[NodeType, NodeStates] = (NodeStates, seq[ConsensusFSMCallbackType[NodeType]])
|
||
|
# Define loose conditions computed from our NodeType
|
||
|
Condition*[NodeType] = proc(node: NodeType): bool
|
||
|
# Define Terminals as a tuple of a Event and (Hash) Table of sequences of (loose) conditions and their respective values computed from NodeType (Truth Table)
|
||
|
TerminalSymbol*[NodeType, EventType] = (Table[EventType, (seq[Condition[NodeType]], seq[bool])])
|
||
|
# Define State Transition Rules LUT of the form ( NonTerminal -> Terminal ) -> NonTerminal )
|
||
|
StateTransitionsRulesLUT*[NodeType, EventType, NodeStates] = Table[
|
||
|
(NonTerminalSymbol[NodeType, NodeStates], TerminalSymbol[NodeType, EventType]),
|
||
|
NonTerminalSymbol[NodeType, NodeStates]]
|
||
|
|
||
|
# FSM type definition
|
||
|
ConsensusFSM*[NodeType, EventType, NodeStates] = ref object
|
||
|
mtx: RLock
|
||
|
state: NonTerminalSymbol[NodeType, NodeStates]
|
||
|
stateTransitionsLUT: StateTransitionsRulesLUT[NodeType, EventType, NodeStates]
|
||
|
|
||
|
# FSM type constructor
|
||
|
proc new*[NodeType, EventType, NodeStates](T: type ConsensusFSM[NodeType, EventType, NodeStates],
|
||
|
lut: StateTransitionsRulesLUT[NodeType, EventType, NodeStates],
|
||
|
startSymbol: NonTerminalSymbol[NodeType, NodeStates]
|
||
|
): T =
|
||
|
result = new(ConsensusFSM[NodeType, EventType, NodeStates])
|
||
|
initRLock(result.mtx)
|
||
|
result.state = startSymbol
|
||
|
result.stateTransitionsLUT = lut
|
||
|
|
||
|
proc computeFSMInputRobustLogic[NodeType, EventType](node: NodeType, event: EventType, rawInput: TerminalSymbol[NodeType, EventType]):
|
||
|
TerminalSymbol[NodeType, EventType] =
|
||
|
var
|
||
|
robustLogicEventTerminal = rawInput[event]
|
||
|
for f, v in robustLogicEventTerminal:
|
||
|
v = f(node)
|
||
|
rawInput[event] = robustLogicEventTerminal
|
||
|
result = rawInput
|
||
|
|
||
|
proc consensusFSMAdvance[NodeType, EventType, NodeStates](fsm: ConsensusFSM[NodeType, EventType, NodeStates], node: NodeType, event: EventType,
|
||
|
rawInput: TerminalSymbol[NodeType, EventType]): NonTerminalSymbol[NodeType, NodeStates] =
|
||
|
withRLock():
|
||
|
var
|
||
|
input = computeFSMInputRobustLogic(node, event, rawInput)
|
||
|
fsm.state = fsm.stateTransitionsLUT[fsm.state, input]
|
||
|
result = fsm.state
|