small_fsm/
lib.rs

1//! # FSM for Rust
2//!
3//! [![Build Status](https://github.com/lovelysunlight/fsm-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/lovelysunlight/fsm-rs/actions/workflows/ci.yml)
4//! [![Latest Version](https://img.shields.io/crates/v/small-fsm.svg)](https://crates.io/crates/small-fsm)
5//! [![Rust Documentation](https://docs.rs/small-fsm/badge.svg)](https://docs.rs/small-fsm)
6//! [![License Badge](https://img.shields.io/badge/license-MIT-blue.svg)](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}