Finite state machines in rust; bendns fork to add types.
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | rust-fsm/src/lib.rs | 195 |
3 files changed, 7 insertions, 200 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a0bab69..bc1fa4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ adheres to [Semantic Versioning][semver]. ## Added * A type alias `StateMachine` for `rust_fsm::StateMachine<Impl>` is now generated inside the said module. -* Supplying ones own enums for state, input and output in the proc-macro. +* Supplying ones own enums for state, input and output in the proc-macro (#10). ## [0.6.2] - 2024-05-11 ### Changed @@ -6,9 +6,9 @@ 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 `StateMachineImpl` trait. This trait -allows a developer to provide a strict state machine definition, e.g. specify -its: +The essential part of this crate is the +[`StateMachineImpl`](trait.StateMachineImpl.html) 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. @@ -141,13 +141,13 @@ state_machine! { The default visibility is private. -#### Custom allphabet types +#### Custom alphabet types You can supply your own types to use as input, output or state. All of them are optional: you can use only one of them or all of them at once if you want to. The current limitation is that you have to supply a fully qualified type path. -```rust +```rust,ignore use rust_fsm::*; pub enum Input { diff --git a/rust-fsm/src/lib.rs b/rust-fsm/src/lib.rs index 98e1c57..95a5ea9 100644 --- a/rust-fsm/src/lib.rs +++ b/rust-fsm/src/lib.rs @@ -1,197 +1,4 @@ -//! 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 -//! [`StateMachineImpl`](trait.StateMachineImpl.html) 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. -//! * Possible states - a set of states this machine could be in. -//! * An output alphabet - a set of entities that the state machine may output -//! as results of its work. -//! * A transition function - a function that changes the state of the state -//! machine based on its current state and the provided input. -//! * An output function - a function that outputs something from the output -//! alphabet based on the current state and the provided inputs. -//! * The initial state of the machine. -//! -//! Note that on the implementation level such abstraction allows build any type -//! of state machines: -//! -//! * A classical state machine by providing only an input alphabet, a set of -//! states and a transition function. -//! * A Mealy machine by providing all entities listed above. -//! * A Moore machine by providing an output function that do not depend on the -//! provided inputs. -//! -//! # Usage in `no_std` environments -//! -//! This library has the feature named `std` which is enabled by default. You -//! may want to import this library as -//! `rust-fsm = { version = "0.6", default-features = false, features = ["dsl"] }` -//! to use it in a `no_std` environment. This only affects error types (the -//! `Error` trait is only available in `std`). -//! -//! The DSL implementation re-export is gated by the feature named `dsl` which -//! is also enabled by default. -//! -//! # 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 -//! use rust_fsm::*; -//! -//! state_machine! { -//! #[derive(Debug)] -//! #[repr(C)] -//! circuit_breaker(Closed) -//! -//! Closed(Unsuccessful) => Open [SetupTimer], -//! Open(TimerTriggered) => HalfOpen, -//! HalfOpen => { -//! Successful => Closed, -//! Unsuccessful => Open [SetupTimer] -//! } -//! } -//! ``` -//! -//! This code sample: -//! -//! * Defines a state machine called `circuit_breaker`; -//! * Derives the `Debug` trait for it. All attributes you use here (like -//! `#[repr(C)]`) will be applied to all types generated by this macro. If you -//! want to apply attributes or a docstring to the `mod` generated by this -//! macro, just put it before the macro invocation. -//! * 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,ignore -//! // Initialize the state machine. The state is `Closed` now. -//! let mut machine = circuit_breaker::StateMachine::new(); -//! // Consume the `Successful` input. No state transition is performed. -//! let _ = machine.consume(&circuit_breaker::Input::Successful); -//! // Consume the `Unsuccesful` input. The machine is moved to the `Open` -//! // state. The output is `SetupTimer`. -//! let output = machine.consume(&circuit_breaker::Input::Unsuccessful).unwrap(); -//! // Check the output -//! if let Some(circuit_breaker::Output::SetupTimer) = output { -//! // Set up the timer... -//! } -//! // Check the state -//! if let circuit_breaker::State::Open = machine.state() { -//! // Do something... -//! } -//! ``` -//! -//! The following entities are generated: -//! -//! * An empty structure `circuit_breaker::Impl` that implements the -//! `StateMachineImpl` trait. -//! * Enums `circuit_breaker::State`, `circuit_breaker::Input` and -//! `circuit_breaker::Output` that represent the state, the input alphabet and -//! the output alphabet respectively. -//! * Type alias `circuit_breaker::StateMachine` that expands to -//! `StateMachine<circuit_breaker::Impl>`. -//! -//! Note that if there is no outputs in the specification, the output alphabet -//! is an empty enum and due to technical limitations of many Rust attributes, -//! no attributes (e.g. `derive`, `repr`) are applied to it. -//! -//! Within the `state_machine` macro you must define at least one state -//! transition. -//! -//! ### Visibility -//! -//! You can specify the module visibility like this: -//! -//! ```rust -//! use rust_fsm::*; -//! -//! state_machine! { -//! pub CircuitBreaker(Closed) -//! -//! Closed(Unsuccessful) => Open [SetupTimer], -//! Open(TimerTriggered) => HalfOpen, -//! HalfOpen => { -//! Successful => Closed, -//! Unsuccessful => Open [SetupTimer], -//! } -//! } -//! ``` -//! -//! The default visibility is private. -//! -//! ### Custom allphabet types -//! -//! You can supply your own types to use as input, output or state. All of them -//! are optional: you can use only one of them or all of them at once if you -//! want to. The current limitation is that you have to supply a fully qualified -//! type path. -//! -//! ```rust,ignore -//! use rust_fsm::*; -//! -//! pub enum Input { -//! Successful, -//! Unsuccessful, -//! TimerTriggered, -//! } -//! -//! pub enum State { -//! Closed, -//! HalfOpen, -//! Open, -//! } -//! -//! pub enum Output { -//! SetupTimer, -//! } -//! -//! state_machine! { -//! #[state_machine(input(crate::Input), state(crate::State), output(crate::Output))] -//! circuit_breaker(Closed) -//! -//! Closed(Unsuccessful) => Open [SetupTimer], -//! Open(TimerTriggered) => HalfOpen, -//! HalfOpen => { -//! Successful => Closed, -//! Unsuccessful => Open [SetupTimer] -//! } -//! } -//! ``` -//! -//! ## 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 -//! `StateMachineImpl` trait and use it in conjuctions with some of the provided -//! wrappers (for now there is only `StateMachine`). -//! -//! You can see an example of the Circuit Breaker state machine in the -//! [project repository][repo]. -//! -//! [repo]: https://github.com/eugene-babichenko/rust-fsm/blob/master/tests/circuit_breaker.rs - +#![doc = include_str!("../../README.md")] #![cfg_attr(not(feature = "std"), no_std)] use core::fmt; |