This project is a fork of a great FSM library https://github.com/hashmismatch/finny.rs. Maintenance of the original project has been paused. This fork is a hobby project maintained in spare time. While there are no significant differences from the upstream (at least at this point), this fork makes an attempt at keeping up with the latest dependencies, code cleanup, and minor features. There are no specific plans to upstream these changes since the original project maintenance is on hold. However, should the author of finny revive the project we'd consider upstreaming accumulated changes.
- Declarative, builder API with a procedural function macro that generate the dispatcher
- Compile-time transition graph validation
- No run-time allocations required,
no_stdsupport - Support for generics within the shared context
- Transition guards and actions
- State regions, also known as orthogonal states
- Event queueing and run-to-completition execution
- Submachines, also known as Hierarchical State Machines
- Timers on states
[dependencies]
finny = "0.2"use finny::{bundled::derive_more, finny_fsm, FsmFactory, FsmResult, decl::{BuiltFsm, FsmBuilder}};
// The context is shared between all guards, actions and transitions. Generics are supported here!
#[derive(Default)]
pub struct MyContext { val: u32 }
// The states are plain structs.
#[derive(Default)]
pub struct MyStateA { n: usize }
#[derive(Default)]
pub struct MyStateB;
// The events are also plain structs. They can have fields.
#[derive(Clone)]
pub struct MyEvent;
// The FSM is generated by a procedural macro
#[finny_fsm]
fn my_fsm(mut fsm: FsmBuilder<MyFsm, MyContext>) -> BuiltFsm {
// The FSM is described using a builder-style API
fsm.state::<MyStateA>()
.on_entry(|state, ctx| {
state.n += 1;
ctx.context.val += 1;
})
.on_event::<MyEvent>()
.transition_to::<MyStateB>()
.guard(|_ev, ctx, _states| { ctx.context.val > 0 })
.action(|_ev, ctx, state_a, state_b| { ctx.context.val += 1; });
fsm.state::<MyStateB>();
fsm.initial_state::<MyStateA>();
fsm.build()
}
// The FSM is built and tested.
fn main() -> FsmResult<()> {
let mut fsm = MyFsm::new(MyContext::default())?;
assert_eq!(0, fsm.val);
fsm.start()?;
let state_a: &MyStateA = fsm.get_state();
assert_eq!(1, state_a.n);
assert_eq!(1, fsm.val);
fsm.dispatch(MyEvent)?;
assert_eq!(2, fsm.val);
Ok(())
}License: MIT OR Apache-2.0