1use core::ops::Deref;
4use cu29_clock::{RobotClock, RobotClockMock};
5
6#[derive(Clone, Debug)]
24pub struct CuContext {
25 pub clock: RobotClock,
27 cl_id: u64,
28 instance_id: u32,
29 subsystem_code: u16,
30 task_ids: &'static [&'static str],
31 current_component_index: Option<usize>,
32 current_task_index: Option<usize>,
33}
34
35impl CuContext {
36 pub fn builder(clock: RobotClock) -> CuContextBuilder {
38 CuContextBuilder {
39 clock,
40 cl_id: 0,
41 instance_id: 0,
42 subsystem_code: 0,
43 task_ids: &[],
44 }
45 }
46
47 pub fn from_clock(clock: RobotClock) -> Self {
53 Self::builder(clock).build()
54 }
55
56 #[cfg(feature = "std")]
62 pub fn new_with_clock() -> Self {
63 Self::from_clock(RobotClock::new())
64 }
65
66 pub fn new_mock_clock() -> (Self, RobotClockMock) {
70 let (clock, mock) = RobotClock::mock();
71 (Self::from_clock(clock), mock)
72 }
73
74 pub(crate) fn new(
76 clock: RobotClock,
77 clid: u64,
78 instance_id: u32,
79 subsystem_code: u16,
80 task_ids: &'static [&'static str],
81 ) -> Self {
82 Self {
83 clock,
84 cl_id: clid,
85 instance_id,
86 subsystem_code,
87 task_ids,
88 current_component_index: None,
89 current_task_index: None,
90 }
91 }
92
93 #[doc(hidden)]
95 pub fn from_runtime_metadata(
96 clock: RobotClock,
97 clid: u64,
98 instance_id: u32,
99 subsystem_code: u16,
100 task_ids: &'static [&'static str],
101 ) -> Self {
102 Self::new(clock, clid, instance_id, subsystem_code, task_ids)
103 }
104
105 pub fn set_current_component(&mut self, component_index: usize) {
107 self.current_component_index = Some(component_index);
108 }
109
110 pub fn clear_current_component(&mut self) {
112 self.current_component_index = None;
113 }
114
115 pub fn set_current_task(&mut self, task_index: usize) {
117 self.current_component_index = Some(task_index);
118 self.current_task_index = Some(task_index);
119 }
120
121 pub fn clear_current_task(&mut self) {
123 self.current_task_index = None;
124 }
125
126 pub fn cl_id(&self) -> u64 {
132 self.cl_id
133 }
134
135 pub fn instance_id(&self) -> u32 {
137 self.instance_id
138 }
139
140 pub fn subsystem_code(&self) -> u16 {
142 self.subsystem_code
143 }
144
145 pub fn current_component_id(&self) -> Option<usize> {
147 self.current_component_index
148 }
149
150 pub fn task_index(&self) -> Option<usize> {
152 self.current_task_index
153 }
154
155 pub fn task_id(&self) -> Option<&'static str> {
157 self.current_task_index
158 .and_then(|idx| self.task_ids.get(idx).copied())
159 }
160}
161
162#[derive(Clone, Debug)]
164pub struct CuContextBuilder {
165 clock: RobotClock,
166 cl_id: u64,
167 instance_id: u32,
168 subsystem_code: u16,
169 task_ids: &'static [&'static str],
170}
171
172impl CuContextBuilder {
173 pub fn cl_id(mut self, cl_id: u64) -> Self {
175 self.cl_id = cl_id;
176 self
177 }
178
179 pub fn instance_id(mut self, instance_id: u32) -> Self {
181 self.instance_id = instance_id;
182 self
183 }
184
185 pub fn task_ids(mut self, task_ids: &'static [&'static str]) -> Self {
187 self.task_ids = task_ids;
188 self
189 }
190
191 pub fn build(self) -> CuContext {
193 CuContext::new(
194 self.clock,
195 self.cl_id,
196 self.instance_id,
197 self.subsystem_code,
198 self.task_ids,
199 )
200 }
201}
202
203impl Deref for CuContext {
204 type Target = RobotClock;
205
206 fn deref(&self) -> &Self::Target {
207 &self.clock
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::CuContext;
214 use cu29_clock::RobotClock;
215
216 #[test]
217 fn default_instance_id_is_zero() {
218 let ctx = CuContext::from_clock(RobotClock::default());
219 assert_eq!(ctx.instance_id(), 0);
220 assert_eq!(ctx.subsystem_code(), 0);
221 }
222
223 #[test]
224 fn builder_overrides_instance_id() {
225 let ctx = CuContext::builder(RobotClock::default())
226 .cl_id(7)
227 .instance_id(42)
228 .build();
229 assert_eq!(ctx.cl_id(), 7);
230 assert_eq!(ctx.instance_id(), 42);
231 assert_eq!(ctx.subsystem_code(), 0);
232 }
233
234 #[test]
235 fn runtime_metadata_sets_subsystem_code() {
236 let ctx = CuContext::from_runtime_metadata(RobotClock::default(), 9, 42, 7, &[]);
237 assert_eq!(ctx.cl_id(), 9);
238 assert_eq!(ctx.instance_id(), 42);
239 assert_eq!(ctx.subsystem_code(), 7);
240 assert_eq!(ctx.current_component_id(), None);
241 assert_eq!(ctx.task_index(), None);
242 }
243
244 #[test]
245 fn task_scope_updates_component_scope() {
246 let mut ctx = CuContext::builder(RobotClock::default())
247 .task_ids(&["task-0"])
248 .build();
249 ctx.set_current_task(0);
250 assert_eq!(ctx.current_component_id(), Some(0));
251 assert_eq!(ctx.task_index(), Some(0));
252 assert_eq!(ctx.task_id(), Some("task-0"));
253 }
254
255 #[test]
256 fn component_scope_can_exist_without_task_scope() {
257 let mut ctx = CuContext::from_clock(RobotClock::default());
258 ctx.set_current_component(7);
259 ctx.clear_current_task();
260 assert_eq!(ctx.current_component_id(), Some(7));
261 assert_eq!(ctx.task_index(), None);
262 assert_eq!(ctx.task_id(), None);
263 }
264}