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.rs | 89 |
1 files changed, 86 insertions, 3 deletions
diff --git a/rust_fsm/src/lib.rs b/rust_fsm/src/lib.rs index d660dec..e98e145 100644 --- a/rust_fsm/src/lib.rs +++ b/rust_fsm/src/lib.rs @@ -1,9 +1,18 @@ //! A framework for building finite state machines in Rust //! //! The `rust-fsm` crate provides a simple and universal framework for building -//! state machines in Rust with minimum effort. The essential part of this crate -//! is the [`StateMachine`] trait. This trait allows a developer to provide a -//! strict state machine definition, e.g. specify its: +//! state machines in Rust with minimum effort. This is achieved by two +//! components: +//! +//! * The `rust-fsm` crate, that provides data types for building state machines +//! and convenience wrappers for these types. +//! * The `rust-fsm-dsl` crate, that contains the `state_machine` macro that +//! parses a simple DSL and generates all boilerplate code for the described +//! state machine. +//! +//! The essential part of this crate is the [`StateMachine`] trait. This trait +//! allows a developer to provide a strict state machine definition, e.g. +//! specify its: //! //! * An input alphabet - a set of entities that the state machine takes as //! inputs and performs state transitions based on them. @@ -27,6 +36,80 @@ //! //! # Use //! +//! Initially this library was designed to build an easy to use DSL for defining +//! state machines on top of it. Using the DSL will require to connect an +//! additional crate `rust-fsm-dsl` (this is due to limitation of the procedural +//! macros system). +//! +//! ## Using the DSL for defining state machines +//! +//! The DSL is parsed by the `state_machine` macro. Here is a little example. +//! +//! ```rust +//! #[macro_use] +//! extern crate rust_fsm_dsl; +//! +//! use use rust_fsm::*; +//! +//! state_machine! { +//! CircuitBreaker(Closed) +//! +//! Closed(Unsuccessful) => Open [SetupTimer], +//! Open(TimerTriggered) => HalfOpen, +//! HalfOpen(Successful) => Closed, +//! HalfOpen(Unsuccessful) => Open [SetupTimer], +//! } +//! ``` +//! +//! This code sample: +//! +//! * Defines a state machine called `CircuitBreaker`; +//! * Sets the initial state of this state machine to `Closed`; +//! * Defines state transitions. For example: on receiving the `Successful` +//! input when in the `HalfOpen` state, the machine must move to the `Closed` +//! state; +//! * Defines outputs. For example: on receiving `Unsuccessful` in the +//! `Closed` state, the machine must output `SetupTimer`. +//! +//! This state machine can be used as follows: +//! +//! ```rust +//! // Initialize the state machine. The state is `Closed` now. +//! let mut machine: StateMachineWrapper<CircuitBreaker> = StateMachineWrapper::new(); +//! // Consume the `Successful` input. No state transition is performed. Output +//! // is `None`. +//! machine.consume_anyway(&CircuitBreakerInput::Successful); +//! // Consume the `Unsuccesful` input. The machine is moved to the `Open` +//! // state. The output is `SetupTimer`. +//! let output = machine.consume_anyway(&CircuitBreakerInput::Unsuccesful); +//! // Check the output +//! if output == Some(CircuitBreakerOutput::SetupTimer) { +//! // Set up the timer... +//! } +//! // Check the state +//! if machine.state() == &CircuitBreakerState::Open { +//! // Do something... +//! } +//! ``` +//! +//! As you can see, the following entities are generated: +//! +//! * An empty structure `CircuitBreaker` that implements the `StateMachine` +//! trait. +//! * Enums `CircuitBreakerState`, `CircuitBreakerInput` and +//! `CircuitBreakerOutput` that represent the state, the input alphabet and +//! the output alphabet respectively. +//! +//! Note that if there is no outputs in the specification, the output alphabet +//! is set to `()`. The set of states and the input alphabet must be non-empty +//! sets. +//! +//! ## Without DSL +//! +//! The `state_machine` macro has limited capabilities (for example, a state +//! cannot carry any additional data), so in certain complex cases a user might +//! want to write a more complex state machine by hand. +//! //! All you need to do to build a state machine is to implement the //! `StateMachine` trait and use it in conjuctions with some of the provided //! wrappers (for now there is only `StateMachineWrapper`). |