Finite state machines in rust; bendns fork to add types.
rust_fsm: merge all definitions into one file
| -rw-r--r-- | rust_fsm/src/lib.rs | 76 | ||||
| -rw-r--r-- | rust_fsm/src/machine.rs | 22 | ||||
| -rw-r--r-- | rust_fsm/src/machine_wrapper.rs | 52 |
3 files changed, 72 insertions, 78 deletions
diff --git a/rust_fsm/src/lib.rs b/rust_fsm/src/lib.rs index 7c5fbd2..f75d412 100644 --- a/rust_fsm/src/lib.rs +++ b/rust_fsm/src/lib.rs @@ -36,8 +36,76 @@ //! //! [repo]: https://github.com/eugene-babichenko/rust-fsm/blob/master/examples/circuit_breaker.rs -mod machine; -mod machine_wrapper; +/// This trait is designed to describe any possible deterministic finite state +/// machine/transducer. This is just a formal definition that may be +/// inconvenient to be used in practical programming, but it is used throughout +/// this library for more practical things. +pub trait StateMachine { + /// The input alphabet. + type Input; + /// The set of possible states. + type State: Copy; + /// The output alphabet. + type Output; + /// The initial state of the machine. + const INITIAL_STATE: Self::State; + /// The transition fuction that outputs a new state based on the current + /// state and the provided input. Outputs `None` when there is no transition + /// for a given combination of the input and the state. + fn transition(state: &Self::State, input: &Self::Input) -> Option<Self::State>; + /// The output function that outputs some value from the output alphabet + /// based on the current state and the given input. Outputs `None` when + /// there is no output for a given combination of the input and the state. + fn output(state: &Self::State, input: &Self::Input) -> Option<Self::Output>; +} -pub use machine::StateMachine; -pub use machine_wrapper::StateMachineWrapper; +/// A convenience wrapper around the `StateMachine` trait that encapsulates the +/// state and transition and output function calls. +pub struct StateMachineWrapper<T: StateMachine> { + state: T::State, +} + +impl<T> StateMachineWrapper<T> +where + T: StateMachine, +{ + /// Create a new instance of this wrapper which encapsulates the initial + /// state. + pub fn new() -> Self { + StateMachineWrapper { + state: T::INITIAL_STATE, + } + } + + /// Consumes the provided input, gives an output and performs a state + /// transition. If a state transition with the current state and the + /// provided input is not allowed, returns an error. + pub fn consume(&mut self, input: &T::Input) -> Result<Option<T::Output>, ()> { + // Operations are reodered for optimization. When the transition is not + // allowed this code exits as soon as possible without calculating the + // output. + let state = match T::transition(&self.state, input) { + Some(state) => state, + None => return Err(()), + }; + let output = T::output(&self.state, input); + self.state = state; + Ok(output) + } + + /// Consumes the provided input, gives an output and performs a state + /// transition. If a state transition is not allowed, this function just + /// provides an output. + pub fn consume_anyway(&mut self, input: &T::Input) -> Option<T::Output> { + let output = T::output(&self.state, input); + if let Some(state) = T::transition(&self.state, input) { + self.state = state; + } + output + } + + /// Returns the current state. + pub fn state(&self) -> &T::State { + &self.state + } +} diff --git a/rust_fsm/src/machine.rs b/rust_fsm/src/machine.rs deleted file mode 100644 index c5f3a32..0000000 --- a/rust_fsm/src/machine.rs +++ /dev/null @@ -1,22 +0,0 @@ -/// This trait is designed to describe any possible deterministic finite state -/// machine/transducer. This is just a formal definition that may be -/// inconvenient to be used in practical programming, but it is used throughout -/// this library for more practical things. -pub trait StateMachine { - /// The input alphabet. - type Input; - /// The set of possible states. - type State: Copy; - /// The output alphabet. - type Output; - /// The initial state of the machine. - const INITIAL_STATE: Self::State; - /// The transition fuction that outputs a new state based on the current - /// state and the provided input. Outputs `None` when there is no transition - /// for a given combination of the input and the state. - fn transition(state: &Self::State, input: &Self::Input) -> Option<Self::State>; - /// The output function that outputs some value from the output alphabet - /// based on the current state and the given input. Outputs `None` when - /// there is no output for a given combination of the input and the state. - fn output(state: &Self::State, input: &Self::Input) -> Option<Self::Output>; -} diff --git a/rust_fsm/src/machine_wrapper.rs b/rust_fsm/src/machine_wrapper.rs deleted file mode 100644 index a48cb1a..0000000 --- a/rust_fsm/src/machine_wrapper.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::StateMachine; - -/// A convenience wrapper around the `StateMachine` trait that encapsulates the -/// state and transition and output function calls. -pub struct StateMachineWrapper<T: StateMachine> { - state: T::State, -} - -impl<T> StateMachineWrapper<T> -where - T: StateMachine, -{ - /// Create a new instance of this wrapper which encapsulates the initial - /// state. - pub fn new() -> Self { - StateMachineWrapper { - state: T::INITIAL_STATE, - } - } - - /// Consumes the provided input, gives an output and performs a state - /// transition. If a state transition with the current state and the - /// provided input is not allowed, returns an error. - pub fn consume(&mut self, input: &T::Input) -> Result<Option<T::Output>, ()> { - // Operations are reodered for optimization. When the transition is not - // allowed this code exits as soon as possible without calculating the - // output. - let state = match T::transition(&self.state, input) { - Some(state) => state, - None => return Err(()), - }; - let output = T::output(&self.state, input); - self.state = state; - Ok(output) - } - - /// Consumes the provided input, gives an output and performs a state - /// transition. If a state transition is not allowed, this function just - /// provides an output. - pub fn consume_anyway(&mut self, input: &T::Input) -> Option<T::Output> { - let output = T::output(&self.state, input); - if let Some(state) = T::transition(&self.state, input) { - self.state = state; - } - output - } - - /// Returns the current state. - pub fn state(&self) -> &T::State { - &self.state - } -} |