1use crate::event::IntoEvent;
2use crate::{
3 action::ActionType, state::StateType, Action, Context, Error, Event, IntoAction, Result, State,
4 Transition,
5};
6use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet};
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
11pub struct Machine<S = State, E = Event>
12where
13 S: Clone + 'static + Default,
14 E: Clone + 'static,
15{
16 pub name: String,
18 pub states: HashMap<String, State>,
20 pub transitions: Vec<Transition>,
22 pub initial: String,
24 pub current_states: HashSet<String>,
26 pub context: Context,
28 #[serde(skip)]
30 pub(crate) entry_actions: HashMap<String, Vec<Action>>,
31 #[serde(skip)]
33 pub(crate) exit_actions: HashMap<String, Vec<Action>>,
34 pub(crate) history: HashMap<String, String>,
36 #[serde(skip)]
38 #[serde(default)]
39 state_mapper: Option<fn(&str) -> S>,
40 #[serde(skip)]
42 current_state_cache: Option<S>,
43 #[serde(skip)]
45 _phantom_s: std::marker::PhantomData<S>,
46 #[serde(skip)]
47 _phantom_e: std::marker::PhantomData<E>,
48}
49
50impl<S, E> Machine<S, E>
51where
52 S: Clone + 'static + Default,
53 E: Clone + 'static,
54{
55 pub fn new<BuilderS, BuilderE>(builder: MachineBuilder<BuilderS, BuilderE>) -> Result<Self>
57 where
58 BuilderS: Clone + 'static + Default,
59 BuilderE: Clone + 'static,
60 {
61 let MachineBuilder {
62 name,
63 states,
64 transitions,
65 initial,
66 entry_actions,
67 exit_actions,
68 context,
69 _phantom_s: _,
70 _phantom_e: _,
71 } = builder;
72
73 if states.is_empty() {
74 return Err(Error::InvalidConfiguration("No states defined".into()));
75 }
76
77 if !states.contains_key(&initial) {
78 return Err(Error::StateNotFound(initial.clone()));
79 }
80
81 let mut machine = Self {
82 name,
83 states,
84 transitions,
85 initial,
86 current_states: HashSet::new(),
87 context: context.unwrap_or_else(Context::new),
88 entry_actions,
89 exit_actions,
90 history: HashMap::new(),
91 state_mapper: None,
92 current_state_cache: None,
93 _phantom_s: std::marker::PhantomData,
94 _phantom_e: std::marker::PhantomData,
95 };
96
97 machine.initialize()?;
99
100 Ok(machine)
101 }
102
103 fn initialize(&mut self) -> Result<()> {
105 let initial_state_id = self.initial.clone();
106 self.enter_state(&initial_state_id, &Event::new("init"))?;
107 Ok(())
108 }
109
110 pub fn send<EV: IntoEvent>(&mut self, event: EV) -> Result<bool> {
112 let event = event.into_event();
113 let mut processed = false;
114
115 let current_states: Vec<_> = self.current_states.iter().cloned().collect();
117
118 for state_id in current_states {
119 if self.process_state_event(&state_id, &event)? {
120 processed = true;
121 }
122 }
123
124 if processed {
126 self.current_state_cache = None;
127 }
128
129 Ok(processed)
130 }
131
132 fn process_state_event(&mut self, state_id: &str, event: &Event) -> Result<bool> {
134 let enabled_transition = self
136 .transitions
137 .iter()
138 .find(|t| t.source == state_id && t.is_enabled(&self.context, event))
139 .cloned();
140
141 if let Some(transition) = enabled_transition {
142 self.execute_transition(&transition, event)?;
144 Ok(true)
145 } else {
146 if let Some(parent_id) = self.get_parent_id(state_id) {
148 self.process_state_event(&parent_id, event)
149 } else {
150 Ok(false)
151 }
152 }
153 }
154
155 fn execute_transition(&mut self, transition: &Transition, event: &Event) -> Result<()> {
157 let source_id = transition.source.clone();
158
159 if transition.target.is_none() {
161 transition.execute_actions(&mut self.context, event);
162 return Ok(());
163 }
164
165 let target_id = transition
166 .target
167 .as_ref()
168 .ok_or_else(|| Error::InvalidTransition("No target state".into()))?
169 .clone();
170
171 self.exit_state(&source_id, event)?;
173
174 transition.execute_actions(&mut self.context, event);
176
177 self.enter_state(&target_id, event)?;
179
180 Ok(())
181 }
182
183 fn enter_state(&mut self, state_id: &str, event: &Event) -> Result<()> {
185 let state = self
186 .states
187 .get(state_id)
188 .ok_or_else(|| Error::StateNotFound(state_id.to_string()))?
189 .clone();
190
191 self.current_states.insert(state_id.to_string());
193
194 if let Some(actions) = self.entry_actions.get(state_id) {
196 for action in actions.clone() {
197 action.execute(&mut self.context, event);
198 }
199 }
200
201 match state.state_type {
203 StateType::Compound => {
204 if let Some(initial) = state.initial {
206 self.enter_state(&initial, event)?;
207 } else {
208 return Err(Error::InvalidConfiguration(format!(
209 "Compound state '{}' has no initial state",
210 state_id
211 )));
212 }
213 }
214 StateType::Parallel => {
215 for child_id in state.children {
217 self.enter_state(&child_id, event)?;
218 }
219 }
220 StateType::History => {
221 if let Some(last_active) = self.history.get(state_id).cloned() {
223 self.enter_state(&last_active, event)?;
224 } else if let Some(parent_id) = self.get_parent_id(state_id) {
225 let parent = self
226 .states
227 .get(&parent_id)
228 .ok_or_else(|| Error::StateNotFound(parent_id.to_string()))?
229 .clone();
230
231 if let Some(initial) = parent.initial {
232 self.enter_state(&initial, event)?;
233 }
234 }
235 }
236 StateType::DeepHistory => {
237 if let Some(last_active) = self.history.get(state_id).cloned() {
240 self.enter_state(&last_active, event)?;
241 } else if let Some(parent_id) = self.get_parent_id(state_id) {
242 let parent = self
243 .states
244 .get(&parent_id)
245 .ok_or_else(|| Error::StateNotFound(parent_id.to_string()))?
246 .clone();
247
248 if let Some(initial) = parent.initial {
249 self.enter_state(&initial, event)?;
250 }
251 }
252 }
253 _ => {} }
255
256 Ok(())
257 }
258
259 fn exit_state(&mut self, state_id: &str, event: &Event) -> Result<()> {
261 let state = self
262 .states
263 .get(state_id)
264 .ok_or_else(|| Error::StateNotFound(state_id.to_string()))?
265 .clone();
266
267 if let Some(parent_id) = self.get_parent_id(state_id) {
269 self.history.insert(parent_id, state_id.to_string());
270 }
271
272 match state.state_type {
274 StateType::Compound | StateType::Parallel => {
275 let active_children: Vec<_> = state
277 .children
278 .iter()
279 .filter(|child_id| self.current_states.contains(*child_id))
280 .cloned()
281 .collect();
282
283 for child_id in active_children {
285 self.exit_state(&child_id, event)?;
286 }
287 }
288 _ => {} }
290
291 if let Some(actions) = self.exit_actions.get(state_id) {
293 for action in actions.clone() {
294 action.execute(&mut self.context, event);
295 }
296 }
297
298 self.current_states.remove(state_id);
300
301 Ok(())
302 }
303
304 fn get_parent_id(&self, state_id: &str) -> Option<String> {
306 self.states
307 .get(state_id)
308 .and_then(|state| state.parent.clone())
309 }
310
311 pub fn is_in(&self, state_id: &str) -> bool {
313 self.current_states.contains(state_id)
314 }
315
316 pub fn to_json(&self) -> Result<String> {
318 let json = serde_json::to_string_pretty(self)?;
319 Ok(json)
320 }
321
322 pub fn from_json(json: &str) -> Result<Self> {
324 let machine: Self = serde_json::from_str(json)?;
325 Ok(machine)
326 }
327
328 pub fn with_state_mapper(mut self, mapper: fn(&str) -> S) -> Self
330 {
331 self.state_mapper = Some(mapper);
332 self
333 }
334
335 pub fn current_state(&self) -> S {
337 if self.current_states.is_empty() {
339 panic!("ステートマシンが初期化されていません。send() を呼び出す前に initialize() を呼び出してください。");
341 }
342
343 let state_id = self.current_states.iter().next().unwrap();
346
347 if let Some(mapper) = self.state_mapper {
349 mapper(state_id)
351 } else {
352 panic!("状態マッパーが設定されていません。Machine::with_state_mapper()を使用してマッパーを設定してください。");
354 }
355 }
356
357 pub fn transition<EV: IntoEvent>(&mut self, event: EV, context: Context) -> Result<S> {
359 self.context = context;
360 let event = event.into_event();
361 let result = self.send(event)?;
362
363 if result {
365 self.current_state_cache = None;
366 }
367
368 Ok(self.current_state())
369 }
370}
371
372pub struct MachineBuilder<S = State, E = Event>
374where
375 S: Clone + 'static + Default,
376 E: Clone + 'static,
377{
378 pub name: String,
380 pub states: HashMap<String, State>,
382 pub transitions: Vec<Transition>,
384 pub initial: String,
386 pub context: Option<Context>,
388 pub(crate) entry_actions: HashMap<String, Vec<Action>>,
390 pub(crate) exit_actions: HashMap<String, Vec<Action>>,
392 _phantom_s: std::marker::PhantomData<S>,
394 _phantom_e: std::marker::PhantomData<E>,
395}
396
397impl<S, E> MachineBuilder<S, E>
398where
399 S: Clone + 'static + Default,
400 E: Clone + 'static,
401{
402 pub fn new(name: impl Into<String>) -> Self {
404 Self {
405 name: name.into(),
406 states: HashMap::new(),
407 transitions: Vec::new(),
408 initial: String::new(),
409 context: None,
410 entry_actions: HashMap::new(),
411 exit_actions: HashMap::new(),
412 _phantom_s: std::marker::PhantomData,
413 _phantom_e: std::marker::PhantomData,
414 }
415 }
416
417 pub fn initial(mut self, state_id: impl Into<String>) -> Self {
419 self.initial = state_id.into();
420 self
421 }
422
423 pub fn state(mut self, state: State) -> Self {
425 if self.states.is_empty() && self.initial.is_empty() {
426 self.initial = state.id.clone();
427 }
428 self.states.insert(state.id.clone(), state);
429 self
430 }
431
432 pub fn transition(mut self, transition: Transition) -> Self {
434 self.transitions.push(transition);
435 self
436 }
437
438 pub fn on_entry<A: IntoAction>(mut self, state_id: impl Into<String>, action: A) -> Self {
440 let state_id = state_id.into();
441 let action = action.into_action(ActionType::Entry);
442 self.entry_actions
443 .entry(state_id)
444 .or_default()
445 .push(action);
446 self
447 }
448
449 pub fn on_exit<A: IntoAction>(mut self, state_id: impl Into<String>, action: A) -> Self {
451 let state_id = state_id.into();
452 let action = action.into_action(ActionType::Exit);
453 self.exit_actions
454 .entry(state_id)
455 .or_default()
456 .push(action);
457 self
458 }
459
460 pub fn context(mut self, context: Context) -> Self {
462 self.context = Some(context);
463 self
464 }
465
466 pub fn build(self) -> Result<Machine<S, E>> {
468 Machine::new(self)
469 }
470}