hierarchical/
hierarchical.rs1use rustate::{
2 Action, ActionType, Context, Machine, MachineBuilder, State, Transition,
3};
4
5fn main() -> rustate::Result<()> {
6 let mut machine = create_player()?;
8
9 println!("Music player state machine created");
10 println!("Current states: {:?}", machine.current_states);
11
12 println!("\nSending PLAY event");
14 machine.send("PLAY")?;
15 println!("Current states: {:?}", machine.current_states);
16
17 println!("\nSending NEXT event");
18 machine.send("NEXT")?;
19 println!("Current states: {:?}", machine.current_states);
20
21 println!("\nSending PAUSE event");
22 machine.send("PAUSE")?;
23 println!("Current states: {:?}", machine.current_states);
24
25 println!("\nSending PLAY event");
26 machine.send("PLAY")?;
27 println!("Current states: {:?}", machine.current_states);
28
29 println!("\nSending POWER event");
30 machine.send("POWER")?;
31 println!("Current states: {:?}", machine.current_states);
32
33 Ok(())
34}
35
36fn create_player() -> rustate::Result<Machine> {
37 let power_off = State::new("powerOff");
39
40 let mut player = State::new_compound("player", "stopped");
41 player.parent = Some("root".to_string());
42
43 let mut stopped = State::new("stopped");
44 stopped.parent = Some("player".to_string());
45
46 let mut playing = State::new_compound("playing", "normal");
47 playing.parent = Some("player".to_string());
48
49 let mut normal = State::new("normal");
50 normal.parent = Some("playing".to_string());
51
52 let mut double_speed = State::new("doubleSpeed");
53 double_speed.parent = Some("playing".to_string());
54
55 let mut paused = State::new("paused");
56 paused.parent = Some("player".to_string());
57
58 let power_toggle = Transition::new("powerOff", "POWER", "player");
60 let power_off_transition = Transition::new("player", "POWER", "powerOff");
61
62 let play = Transition::new("stopped", "PLAY", "playing");
63 let stop = Transition::new("playing", "STOP", "stopped");
64 let pause = Transition::new("playing", "PAUSE", "paused");
65 let resume = Transition::new("paused", "PLAY", "playing");
66
67 let speed_up = Transition::new("normal", "SPEED_UP", "doubleSpeed");
68 let speed_normal = Transition::new("doubleSpeed", "SPEED_NORMAL", "normal");
69
70 let next_track = Transition::internal_transition("playing", "NEXT");
71 let prev_track = Transition::internal_transition("playing", "PREV");
72
73 let log_power_on = Action::new("logPowerOn", ActionType::Entry, |_ctx, _evt| {
75 println!("Power ON - Player ready")
76 });
77
78 let log_power_off = Action::new("logPowerOff", ActionType::Entry, |_ctx, _evt| {
79 println!("Power OFF")
80 });
81
82 let log_playing = Action::new("logPlaying", ActionType::Entry, |_ctx, _evt| {
83 println!("Playing track")
84 });
85
86 let log_stopped = Action::new("logStopped", ActionType::Entry, |_ctx, _evt| {
87 println!("Stopped")
88 });
89
90 let log_paused = Action::new("logPaused", ActionType::Entry, |_ctx, _evt| {
91 println!("Paused")
92 });
93
94 let log_double_speed = Action::new("logDoubleSpeed", ActionType::Entry, |_ctx, _evt| {
95 println!("Playing at double speed")
96 });
97
98 let log_normal_speed = Action::new("logNormalSpeed", ActionType::Entry, |_ctx, _evt| {
99 println!("Playing at normal speed")
100 });
101
102 let next_track_action = Action::new("nextTrack", ActionType::Transition, |ctx, _evt| {
103 let current_track = ctx.get::<usize>("track").unwrap_or(0);
104 let next_track = current_track + 1;
105 println!("Changing to track {}", next_track);
106 let _ = ctx.set("track", next_track);
107 });
108
109 let prev_track_action = Action::new("prevTrack", ActionType::Transition, |ctx, _evt| {
110 let current_track = ctx.get::<usize>("track").unwrap_or(0);
111 let prev_track = if current_track > 0 {
112 current_track - 1
113 } else {
114 0
115 };
116 println!("Changing to track {}", prev_track);
117 let _ = ctx.set("track", prev_track);
118 });
119
120 let mut context = Context::new();
122 let _ = context.set("track", 0);
123
124 let mut next_track = next_track;
126 next_track.with_action(next_track_action);
127
128 let mut prev_track = prev_track;
129 prev_track.with_action(prev_track_action);
130
131 let machine = MachineBuilder::new("musicPlayer")
132 .initial("powerOff")
133 .state(power_off)
134 .state(player)
135 .state(stopped)
136 .state(playing)
137 .state(normal)
138 .state(double_speed)
139 .state(paused)
140 .transition(power_toggle)
141 .transition(power_off_transition)
142 .transition(play)
143 .transition(stop)
144 .transition(pause)
145 .transition(resume)
146 .transition(speed_up)
147 .transition(speed_normal)
148 .transition(next_track)
149 .transition(prev_track)
150 .on_entry("player", log_power_on)
151 .on_entry("powerOff", log_power_off)
152 .on_entry("playing", log_playing)
153 .on_entry("stopped", log_stopped)
154 .on_entry("paused", log_paused)
155 .on_entry("doubleSpeed", log_double_speed)
156 .on_entry("normal", log_normal_speed)
157 .context(context)
158 .build()?;
159
160 Ok(machine)
161}