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 #[cfg(feature = "std")]
162 pub(crate) fn with_cl_id(&self, cl_id: u64) -> Self {
163 let mut context = self.clone();
164 context.cl_id = cl_id;
165 context
166 }
167}
168
169#[derive(Clone, Debug)]
171pub struct CuContextBuilder {
172 clock: RobotClock,
173 cl_id: u64,
174 instance_id: u32,
175 subsystem_code: u16,
176 task_ids: &'static [&'static str],
177}
178
179impl CuContextBuilder {
180 pub fn cl_id(mut self, cl_id: u64) -> Self {
182 self.cl_id = cl_id;
183 self
184 }
185
186 pub fn instance_id(mut self, instance_id: u32) -> Self {
188 self.instance_id = instance_id;
189 self
190 }
191
192 pub fn task_ids(mut self, task_ids: &'static [&'static str]) -> Self {
194 self.task_ids = task_ids;
195 self
196 }
197
198 pub fn build(self) -> CuContext {
200 CuContext::new(
201 self.clock,
202 self.cl_id,
203 self.instance_id,
204 self.subsystem_code,
205 self.task_ids,
206 )
207 }
208}
209
210impl Deref for CuContext {
211 type Target = RobotClock;
212
213 fn deref(&self) -> &Self::Target {
214 &self.clock
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::CuContext;
221 use cu29_clock::RobotClock;
222
223 #[test]
224 fn default_instance_id_is_zero() {
225 let ctx = CuContext::from_clock(RobotClock::default());
226 assert_eq!(ctx.instance_id(), 0);
227 assert_eq!(ctx.subsystem_code(), 0);
228 }
229
230 #[test]
231 fn builder_overrides_instance_id() {
232 let ctx = CuContext::builder(RobotClock::default())
233 .cl_id(7)
234 .instance_id(42)
235 .build();
236 assert_eq!(ctx.cl_id(), 7);
237 assert_eq!(ctx.instance_id(), 42);
238 assert_eq!(ctx.subsystem_code(), 0);
239 }
240
241 #[test]
242 fn runtime_metadata_sets_subsystem_code() {
243 let ctx = CuContext::from_runtime_metadata(RobotClock::default(), 9, 42, 7, &[]);
244 assert_eq!(ctx.cl_id(), 9);
245 assert_eq!(ctx.instance_id(), 42);
246 assert_eq!(ctx.subsystem_code(), 7);
247 assert_eq!(ctx.current_component_id(), None);
248 assert_eq!(ctx.task_index(), None);
249 }
250
251 #[test]
252 fn task_scope_updates_component_scope() {
253 let mut ctx = CuContext::builder(RobotClock::default())
254 .task_ids(&["task-0"])
255 .build();
256 ctx.set_current_task(0);
257 assert_eq!(ctx.current_component_id(), Some(0));
258 assert_eq!(ctx.task_index(), Some(0));
259 assert_eq!(ctx.task_id(), Some("task-0"));
260 }
261
262 #[test]
263 fn component_scope_can_exist_without_task_scope() {
264 let mut ctx = CuContext::from_clock(RobotClock::default());
265 ctx.set_current_component(7);
266 ctx.clear_current_task();
267 assert_eq!(ctx.current_component_id(), Some(7));
268 assert_eq!(ctx.task_index(), None);
269 assert_eq!(ctx.task_id(), None);
270 }
271}