1use crate::lifecycle::ComponentAction;
14use crate::return_code::ReturnCode;
15
16pub trait DataFlowComponentAction: ComponentAction {
23 fn on_execute(&mut self, _exec_handle: u32) -> ReturnCode {
25 ReturnCode::Ok
26 }
27 fn on_state_update(&mut self, _exec_handle: u32) -> ReturnCode {
29 ReturnCode::Ok
30 }
31 fn on_rate_changed(&mut self, _exec_handle: u32) -> ReturnCode {
34 ReturnCode::Ok
35 }
36}
37
38pub trait FsmComponentAction: ComponentAction {
41 fn on_action(&mut self, _exec_handle: u32) -> ReturnCode {
44 ReturnCode::Ok
45 }
46}
47
48pub trait ModeOfOperation: core::fmt::Debug + Copy + PartialEq + Eq {
52 fn name(&self) -> &str;
54}
55
56pub trait MultiModeComponentAction<M: ModeOfOperation>: ComponentAction {
59 fn on_mode_changed(&mut self, _from: M, _to: M, _exec_handle: u32) -> ReturnCode {
62 ReturnCode::Ok
63 }
64}
65
66#[cfg(test)]
67#[allow(clippy::expect_used)]
68mod tests {
69 use super::*;
70
71 struct DataFlowStub {
72 executes: u32,
73 state_updates: u32,
74 rate_changes: u32,
75 }
76 impl ComponentAction for DataFlowStub {}
77 impl DataFlowComponentAction for DataFlowStub {
78 fn on_execute(&mut self, _h: u32) -> ReturnCode {
79 self.executes += 1;
80 ReturnCode::Ok
81 }
82 fn on_state_update(&mut self, _h: u32) -> ReturnCode {
83 self.state_updates += 1;
84 ReturnCode::Ok
85 }
86 fn on_rate_changed(&mut self, _h: u32) -> ReturnCode {
87 self.rate_changes += 1;
88 ReturnCode::Ok
89 }
90 }
91
92 #[test]
93 fn data_flow_callbacks_are_invoked_independently() {
94 let mut s = DataFlowStub {
96 executes: 0,
97 state_updates: 0,
98 rate_changes: 0,
99 };
100 s.on_execute(0);
101 s.on_execute(0);
102 s.on_state_update(0);
103 s.on_rate_changed(0);
104 assert_eq!(s.executes, 2);
105 assert_eq!(s.state_updates, 1);
106 assert_eq!(s.rate_changes, 1);
107 }
108
109 struct FsmStub {
110 actions: u32,
111 }
112 impl ComponentAction for FsmStub {}
113 impl FsmComponentAction for FsmStub {
114 fn on_action(&mut self, _h: u32) -> ReturnCode {
115 self.actions += 1;
116 ReturnCode::Ok
117 }
118 }
119
120 #[test]
121 fn fsm_on_action_is_invoked_per_event() {
122 let mut s = FsmStub { actions: 0 };
124 s.on_action(0);
125 s.on_action(0);
126 s.on_action(0);
127 assert_eq!(s.actions, 3);
128 }
129
130 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
131 enum AutoMode {
132 Idle,
133 Driving,
134 Charging,
135 }
136
137 impl ModeOfOperation for AutoMode {
138 fn name(&self) -> &str {
139 match self {
140 Self::Idle => "Idle",
141 Self::Driving => "Driving",
142 Self::Charging => "Charging",
143 }
144 }
145 }
146
147 #[test]
148 fn mode_of_operation_provides_string_name() {
149 assert_eq!(AutoMode::Idle.name(), "Idle");
151 assert_eq!(AutoMode::Driving.name(), "Driving");
152 assert_eq!(AutoMode::Charging.name(), "Charging");
153 }
154
155 struct ModeStub {
156 transitions: alloc::vec::Vec<(AutoMode, AutoMode)>,
157 }
158 impl ComponentAction for ModeStub {}
159 impl MultiModeComponentAction<AutoMode> for ModeStub {
160 fn on_mode_changed(&mut self, from: AutoMode, to: AutoMode, _h: u32) -> ReturnCode {
161 self.transitions.push((from, to));
162 ReturnCode::Ok
163 }
164 }
165
166 #[test]
167 fn multi_mode_on_mode_changed_records_transition() {
168 let mut s = ModeStub {
170 transitions: alloc::vec::Vec::new(),
171 };
172 s.on_mode_changed(AutoMode::Idle, AutoMode::Driving, 1);
173 s.on_mode_changed(AutoMode::Driving, AutoMode::Charging, 1);
174 assert_eq!(
175 s.transitions,
176 alloc::vec![
177 (AutoMode::Idle, AutoMode::Driving),
178 (AutoMode::Driving, AutoMode::Charging),
179 ]
180 );
181 }
182}