tokio_fsm/lib.rs
1//! # tokio-fsm
2//!
3//! **Compile-time validated, zero-overhead async finite state machines for [Tokio](https://tokio.rs).**
4//!
5//! `tokio-fsm` allows you to define complex asynchronous state machines using a declarative macro.
6//! It eliminates the boilerplate of manual event loops, channel management, and state transitions
7//! while ensuring that your FSM logic is verified at compile-time.
8//!
9//! ## Problem Statement
10//!
11//! Traditional FSM implementations in Rust often fall into two categories:
12//! 1. **Hand-rolled**: Extremely fast and flexible, but error-prone. Managing `mpsc` channels,
13//! `tokio::select!` loops, and ensuring "invalid state" transitions don't occur requires significant boilerplate.
14//! 2. **Runtime Engines**: Flexible, but often involve virtual dispatch, heavy allocations, or
15//! complex trait hierarchies that add overhead and obfuscate the mental model.
16//!
17//! `tokio-fsm` provides a **third way**: Write standard Rust `impl` blocks, and let the proc-macro
18//! generate the high-performance, type-safe boilerplate for you.
19//!
20//! ## Core Concepts
21//!
22//! ### States & Events
23//! States and Events are **discovered** automatically from your `#[on]` handlers. You don't need to
24//! manually define enums for them—the macro generates a `[FsmName]State` and `[FsmName]Event` enum for you.
25//!
26//! ### Context
27//! The `Context` is the shared, mutable data owned by the FSM. Every handler has access to
28//! `&mut self.context`.
29//!
30//! ### Transitions
31//! Handlers return a `Transition<NextState>`. This explicitly defines the next state the FSM
32//! should move to. The macro validates that `NextState` is a known state and that the transition
33//! is reachable.
34//!
35//! ### Timeouts
36//! `tokio-fsm` supports state-level timeouts via `#[state_timeout]`. These are implemented using
37//! single, stack-pinned `tokio::time::Sleep` futures, ensuring zero heap allocations during transitions.
38//!
39//! ## Architecture
40//!
41//! 1. **Validation Layer**: At compile-time, the macro builds a directed graph of your FSM. It
42//! verifies that all states are reachable and that transitions are logically consistent.
43//! 2. **Codegen Layer**: Generates a tight, state-gated match loop. There is **no runtime engine**;
44//! the generated code is identical to what a senior engineer would write by hand.
45//!
46//! ## Example: Basic Worker
47//!
48//! ```rust
49//! use tokio_fsm::{fsm, Transition};
50//!
51//! pub struct WorkerContext { iterations: usize }
52//!
53//! #[fsm(initial = Idle)]
54//! impl WorkerFsm {
55//! type Context = WorkerContext;
56//! type Error = std::convert::Infallible;
57//!
58//! #[on(state = Idle, event = Start)]
59//! async fn on_start(&mut self) -> Transition<Running> {
60//! Transition::to(Running)
61//! }
62//!
63//! #[on(state = Running, event = Tick)]
64//! async fn on_tick(&mut self) -> Transition<Running> {
65//! self.context.iterations += 1;
66//! Transition::to(Running)
67//! }
68//! }
69//! ```
70//!
71//! ## FAQ & Troubleshooting
72//!
73//! ### Why is my event ignored?
74//! If an event is sent while the FSM is in a state where no `#[on(state = current, event = event)]`
75//! handler is defined, the event is silently dropped by default. This is intentional to prevent
76//! deadlocks in high-throughput systems.
77//!
78//! ### Compile Error: "State X not found"
79//! Ensure that state `X` is either the `initial` state or is used as a target in a `Transition<X>`
80//! or a source in an `#[on(state = X, ...)]` attribute.
81//!
82//! ### Compile Error: "Event Y not found"
83//! Ensure that event `Y` is defined in at least one `#[on(..., event = Y)]` attribute.
84
85mod core;
86
87#[doc(inline)]
88pub use tokio_fsm_macros::*;
89
90#[doc(inline)]
91pub use crate::core::*;