pub struct Machine<S, E> { /* private fields */ }Expand description
A generic finite state machine.
§Type Parameters
S: The state type. Must implementEq + Hash + Clone.E: The event type. Must implementEq + Hash + Clone.
Implementations§
Source§impl<S, E> Machine<S, E>
impl<S, E> Machine<S, E>
Sourcepub fn new(initial_state: S) -> Self
pub fn new(initial_state: S) -> Self
Create a new state machine with the given initial state.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn state(&self) -> &S
pub fn state(&self) -> &S
A reference to the current state of the machine.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Source§impl<S, E> Machine<S, E>
impl<S, E> Machine<S, E>
Sourcepub fn states(&self) -> impl Iterator<Item = &S>
pub fn states(&self) -> impl Iterator<Item = &S>
Returns an iterator over all states known to the machine.
Examples found in repository?
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn events(&self) -> impl Iterator<Item = &E>
pub fn events(&self) -> impl Iterator<Item = &E>
Returns an iterator over all events the machine can react to.
Examples found in repository?
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn triggerable_events(&self) -> impl Iterator<Item = &E>
pub fn triggerable_events(&self) -> impl Iterator<Item = &E>
Returns an iterator over events valid from the current state.
Only events that have a defined transition from the machine’s current state are included.
Examples found in repository?
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Source§impl<S, E> Machine<S, E>
impl<S, E> Machine<S, E>
Sourcepub fn when(&mut self, event: E, state: S, new_state: S)
pub fn when(&mut self, event: E, state: S, new_state: S)
When event occurs in state, move to new_state.
Multiple calls to when for the same (event, state) will overwrite
the previous new_state.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn when_iter<I>(&mut self, event: E, mapping: I)where
I: IntoIterator<Item = (S, S)>,
pub fn when_iter<I>(&mut self, event: E, mapping: I)where
I: IntoIterator<Item = (S, S)>,
Define multiple transitions for a single event.
The mapping iterator should yield (from_state, to_state) pairs.
Examples found in repository?
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn on_enter<F>(&mut self, state: S, callback: F)where
F: Fn(E) + 'static,
pub fn on_enter<F>(&mut self, state: S, callback: F)where
F: Fn(E) + 'static,
Register a callback that only cares about the event (no payload).
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}Sourcepub fn on_enter_with<P, F>(&mut self, state: S, callback: F)
pub fn on_enter_with<P, F>(&mut self, state: S, callback: F)
Register a callback that expects a payload of type P.
The callback takes the triggering event and a payload of type P. It
will only be invoked if the payload downcasts to P successfully.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn on_transition<F>(&mut self, callback: F)
pub fn on_transition<F>(&mut self, callback: F)
Register a callback to fire on any state transition.
Works similarly to on_enter, but the callback runs regardless of the
specific state entered.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn on_transition_with<P, F>(&mut self, callback: F)
pub fn on_transition_with<P, F>(&mut self, callback: F)
Register a callback to fire on any state transition with a payload of
type P.
Works similarly to on_enter_with, but the callback runs regardless of
the specific state, and only if the payload downcasts to P
successfully.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn trigger(&mut self, event: &E) -> Result<(), MachineError>
pub fn trigger(&mut self, event: &E) -> Result<(), MachineError>
Trigger the given event on the machine without any payload.
If the event is defined for the current state, the machine will transition to the corresponding new state and invoke any registered callbacks.
§Errors
- Returns
MachineError::EventInvalidif the event is not defined in this state machine. - Returns
MachineError::StateInvalidif the event has no transition defined for the machine’s current state.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}Sourcepub fn trigger_with<P>(
&mut self,
event: &E,
payload: &P,
) -> Result<(), MachineError>where
P: 'static,
pub fn trigger_with<P>(
&mut self,
event: &E,
payload: &P,
) -> Result<(), MachineError>where
P: 'static,
Trigger the given event on the machine with an associated payload.
The payload will be provided to callbacks that accept the payload type
P. If the event is defined for the current state, the machine will
perform the transition and invoke any matching callbacks.
§Errors
- Returns
MachineError::EventInvalidif the event is not defined in this state machine. - Returns
MachineError::StateInvalidif no transition is defined for the machine’s current state with the given event.
Examples found in repository?
5fn main() {
6 let mut nano = Machine::new("locked");
7
8 // Define valid transitions.
9 nano.when("insert coin", "locked", "unlocked");
10 nano.when("turn knob", "unlocked", "locked");
11
12 // State-specific callbacks without payload.
13 nano.on_enter("unlocked", |e| println!("Unlocked via {:?}", e));
14 nano.on_enter("locked", |e| println!("Locked via {:?}", e));
15
16 // State-specific callback with a u32 payload.
17 nano.on_enter_with("unlocked", |e, amount: &u32| {
18 println!("Received {} cents via {:?}", amount, e);
19 });
20
21 // Global callbacks.
22 nano.on_transition(|e| println!("Global - event {:?}", e));
23 nano.on_transition_with(|e, amount: &u32| {
24 println!("Global - saw {} cents via {:?}", amount, e);
25 });
26 nano.on_transition_with(|e, msg: &String| {
27 println!("Global - saw \"{}\" via {:?}", msg, e);
28 });
29
30 // Prints:
31 // Unlocked via "insert coin"
32 // Global - event "insert coin"
33 nano.trigger(&"insert coin").unwrap();
34
35 // Prints:
36 // Locked via "turn knob"
37 // Global - event "turn knob"
38 // Global - saw "voucher" via "turn knob"
39 nano.trigger_with(&"turn knob", &"voucher".to_string()).unwrap();
40
41 // Prints:
42 // Unlocked via "insert coin"
43 // Received 50 cents via "insert coin"
44 // Global - event "insert coin"
45 // Global - saw 50 cents via "insert coin"
46 nano.trigger_with(&"insert coin", &50u32).unwrap();
47
48 // Final state: "unlocked"
49 println!("Final state: {:?}", nano.state());
50}More examples
24fn main() {
25 // Create the machine in the Created state.
26 let mut nano = Machine::new(OrderState::Created);
27
28 // Define transitions one-by-one.
29 nano.when(OrderEvent::Pay, OrderState::Created, OrderState::Paid);
30 nano.when(OrderEvent::Ship, OrderState::Paid, OrderState::Shipped);
31 nano.when(OrderEvent::Deliver, OrderState::Shipped, OrderState::Delivered);
32
33 // Define Cancel for both Created and Paid using when_iter.
34 nano.when_iter(
35 OrderEvent::Cancel,
36 [
37 (OrderState::Created, OrderState::Cancelled),
38 (OrderState::Paid, OrderState::Cancelled),
39 ],
40 );
41
42 // ─── State-specific hooks ───────────────────────────────────────────────
43 // On Paid: log payment amount.
44 nano.on_enter_with(OrderState::Paid, |evt, amount: &u32| {
45 println!("✔ Payment {:?}: {}¢ received", evt, amount);
46 });
47
48 // On Shipped: log tracking code.
49 nano.on_enter_with(OrderState::Shipped, |_evt, tracking: &String| {
50 println!("🚚 Order shipped! Tracking code: {}", tracking);
51 });
52
53 // On Delivered: confirmation.
54 nano.on_enter_with(OrderState::Delivered, |_evt, _: &()| {
55 println!("📦 Order delivered. Thank you!");
56 });
57
58 // On Cancelled: show cancellation reason.
59 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
60 println!("❌ Order cancelled: {}", reason);
61 });
62
63 // ─── Global hooks ───────────────────────────────────────────────────────
64 // Fires on *every* transition (no payload).
65 nano.on_transition(|evt| {
66 println!("🔄 Transition via event: {:?}", evt);
67 });
68
69 // Fires on *every* transition *with* a u32 payload (e.g. payments).
70 nano.on_transition_with(|evt, amount: &u32| {
71 println!("🌐 Global saw {}¢ payment via {:?}", amount, evt);
72 });
73
74 // Fires on *every* transition *with* a String payload
75 // (e.g. tracking codes or cancellation reasons).
76 nano.on_transition_with(|evt, text: &String| {
77 println!("🌐 Global saw string payload {:?}: {}", evt, text);
78 });
79 // Inspect machine metadata:
80 println!("All states: {:?}", nano.states().cloned().collect::<Vec<_>>());
81 println!("All events: {:?}", nano.events().cloned().collect::<Vec<_>>());
82 println!(
83 "Triggerable now ({:?}): {:?}",
84 nano.state(),
85 nano.triggerable_events().cloned().collect::<Vec<_>>()
86 );
87 println!();
88
89 // Simulate a successful order:
90 // Pay with payload.
91 nano.trigger_with(&OrderEvent::Pay, &2_500u32)
92 .expect("Should transition to Paid");
93 // Ship with payload.
94 nano.trigger_with(&OrderEvent::Ship, &"TRACK1234".to_string())
95 .expect("Should transition to Shipped");
96 // Deliver without payload.
97 nano.trigger(&OrderEvent::Deliver).expect("Should transition to Delivered");
98 println!("\nFinal state: {:?}\n", nano.state());
99
100 // Attempt an invalid transition (Pay after Delivered).
101 match nano.trigger(&OrderEvent::Pay) {
102 Ok(_) => println!("Unexpectedly succeeded!"),
103 Err(e) => println!("Error trying to pay in {:?}: {}", nano.state(), e),
104 }
105
106 // Create a fresh order and cancel it early.
107 let mut nano = Machine::new(OrderState::Created);
108 nano.when_iter(
109 OrderEvent::Cancel,
110 [
111 (OrderState::Created, OrderState::Cancelled),
112 (OrderState::Paid, OrderState::Cancelled),
113 ],
114 );
115 // Re-attach only the Cancel callback.
116 nano.on_enter_with(OrderState::Cancelled, |_evt, reason: &String| {
117 println!("Order #2 cancelled reason: {}", reason);
118 });
119 // Cancel with a payload.
120 nano.trigger_with(
121 &OrderEvent::Cancel,
122 &"Customer changed mind".to_string(),
123 )
124 .unwrap();
125
126 println!("Order #2 final: {:?}", nano.state());
127}