small_fsm/lib.rs
1//! # FSM for Rust
2//!
3//! [](https://github.com/lovelysunlight/fsm-rs/actions/workflows/ci.yml)
4//! [](https://crates.io/crates/small-fsm)
5//! [](https://docs.rs/small-fsm)
6//! [](https://raw.githubusercontent.com/lovelysunlight/fsm-rs/main/LICENSE)
7//!
8//! Finite State Machine for Rust.
9//!
10//! The full version of the README can be found on [GitHub](https://github.com/lovelysunlight/fsm-rs).
11//!
12//! # Including Fsm in Your Project
13//!
14//! ```toml
15//! [dependencies]
16//! small-fsm = "0.1"
17//!
18//! # optional, you can also use `strum` to work with enums and strings easier in Rust.
19//! # strum = { version = "0.26", features = ["derive"] }
20//! ```
21//!
22//! # Example
23//!
24//! ```rust
25//! use small_fsm::{Closure, EventDesc, FSMState, HookType, FSM};
26//! use std::collections::HashMap;
27//! use strum::AsRefStr;
28//! use strum::Display;
29//!
30//! #[derive(Display, AsRefStr, Debug, Clone, Hash, PartialEq, Eq)]
31//! enum StateTag {
32//! #[strum(serialize = "opened")]
33//! Opened,
34//! #[strum(serialize = "closed")]
35//! Closed,
36//! }
37//! impl FSMState for StateTag {}
38//! impl AsRef<Self> for StateTag {
39//! fn as_ref(&self) -> &Self {
40//! &self
41//! }
42//! }
43//!
44//! #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
45//! pub enum MyError {
46//! Unknown,
47//! }
48//!
49//! impl std::fmt::Display for MyError {
50//! fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
51//! match self {
52//! MyError::Unknown => write!(f, "unknown error"),
53//! }
54//! }
55//! }
56//!
57//! impl std::error::Error for MyError {
58//! fn description(&self) -> &str {
59//! match self {
60//! MyError::Unknown => "unknown error.",
61//! }
62//! }
63//! }
64//!
65//! let mut fsm: FSM<_, Vec<u32>, _> = FSM::new(
66//! StateTag::Closed,
67//! vec![
68//! EventDesc {
69//! name: "open",
70//! src: vec![StateTag::Closed],
71//! dst: StateTag::Opened,
72//! },
73//! EventDesc {
74//! name: "close",
75//! src: vec![StateTag::Opened],
76//! dst: StateTag::Closed,
77//! },
78//! ],
79//! HashMap::from([
80//! (
81//! HookType::BeforeEvent,
82//! Closure::new(|_e| -> Result<(), MyError> { Ok(()) }),
83//! ),
84//! (
85//! HookType::AfterEvent,
86//! Closure::new(|_e| -> Result<(), MyError> { Ok(()) }),
87//! ),
88//! ]),
89//! );
90//!
91//! assert_eq!(StateTag::Closed, fsm.get_current());
92//!
93//! assert!(fsm.on_event("open", None).is_ok());
94//! assert_eq!(StateTag::Opened, fsm.get_current());
95//!
96//! assert!(fsm.on_event("close", None).is_ok());
97//! assert_eq!(StateTag::Closed, fsm.get_current());
98//! ```
99//!
100
101mod action;
102mod error;
103mod event;
104mod fsm;
105
106pub use self::fsm::{CallbackType, EventDesc, FSMState, HookType, FSM};
107pub use action::{Action, Closure};
108pub use error::FSMError;
109
110#[cfg(test)]
111mod tests {
112 use strum::AsRefStr;
113 use strum::Display;
114
115 #[derive(Debug, Display, AsRefStr)]
116 enum TestTag {
117 #[strum(serialize = "Opened")]
118 Opened,
119 #[strum(serialize = "Closed")]
120 Closed,
121 }
122
123 #[test]
124 fn test_enum_display() {
125 assert_eq!("Opened", TestTag::Opened.to_string());
126 assert_eq!("Closed", TestTag::Closed.to_string());
127 }
128
129 #[test]
130 fn test_enum_as_ref() {
131 assert_eq!("Opened", TestTag::Opened.as_ref());
132 assert_eq!("Closed", TestTag::Closed.as_ref());
133 }
134}