Finite state machines in rust; bendns fork to add types.
Diffstat (limited to 'rust_fsm/src/lib.rs')
-rw-r--r--rust_fsm/src/lib.rs76
1 files changed, 72 insertions, 4 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
+ }
+}