Skip to main content

cu29_runtime/
context.rs

1//! User-facing execution context passed to task and bridge process callbacks.
2
3use core::ops::Deref;
4use cu29_clock::{RobotClock, RobotClockMock};
5
6/// Execution context passed to task and bridge callbacks.
7///
8/// `CuContext` provides callback code with:
9/// - time access through `clock` and `Deref<Target = RobotClock>`
10/// - current execution sequence id via `cl_id()`
11/// - current task metadata via `task_id()` / `task_index()`
12///
13/// The execution sequence id matches the copper-list id of the iteration being
14/// processed. It is also available in other lifecycle callbacks
15/// (`start`/`preprocess`/`postprocess`/`stop`) for continuity, but outside
16/// `process` callbacks it must not be treated as a live copper-list handle.
17///
18/// The runtime creates one context per execution loop and updates transient
19/// fields such as the currently executing task before each callback.
20#[derive(Clone, Debug)]
21pub struct CuContext {
22    /// Runtime clock. Kept as a field for direct access (`context.clock.now()`).
23    pub clock: RobotClock,
24    cl_id: u64,
25    task_ids: &'static [&'static str],
26    current_task_index: Option<usize>,
27}
28
29impl CuContext {
30    /// Starts a context builder from a clock.
31    pub fn builder(clock: RobotClock) -> CuContextBuilder {
32        CuContextBuilder {
33            clock,
34            cl_id: 0,
35            task_ids: &[],
36        }
37    }
38
39    /// Creates a context from an existing clock with default metadata.
40    ///
41    /// Defaults:
42    /// - `cl_id = 0`
43    /// - no task id table
44    pub fn from_clock(clock: RobotClock) -> Self {
45        Self::builder(clock).build()
46    }
47
48    /// Creates a context backed by a real robot clock.
49    ///
50    /// Defaults:
51    /// - `cl_id = 0`
52    /// - no task id table
53    #[cfg(feature = "std")]
54    pub fn new_with_clock() -> Self {
55        Self::from_clock(RobotClock::new())
56    }
57
58    /// Creates a context backed by a mock clock.
59    ///
60    /// Returns both the context and its [`RobotClockMock`] control handle.
61    pub fn new_mock_clock() -> (Self, RobotClockMock) {
62        let (clock, mock) = RobotClock::mock();
63        (Self::from_clock(clock), mock)
64    }
65
66    /// Internal constructor used by runtime internals and code generation.
67    pub(crate) fn new(clock: RobotClock, clid: u64, task_ids: &'static [&'static str]) -> Self {
68        Self {
69            clock,
70            cl_id: clid,
71            task_ids,
72            current_task_index: None,
73        }
74    }
75
76    /// Sets the currently executing task index.
77    pub fn set_current_task(&mut self, task_index: usize) {
78        self.current_task_index = Some(task_index);
79    }
80
81    /// Clears the currently executing task.
82    pub fn clear_current_task(&mut self) {
83        self.current_task_index = None;
84    }
85
86    /// Returns the current execution sequence id.
87    ///
88    /// In `process` callbacks, this value is the id of the copper-list being
89    /// processed. In other lifecycle callbacks, this value is still meaningful
90    /// for sequencing but does not imply that a copper-list instance is alive.
91    pub fn cl_id(&self) -> u64 {
92        self.cl_id
93    }
94
95    /// Returns the current task index, if any.
96    pub fn task_index(&self) -> Option<usize> {
97        self.current_task_index
98    }
99
100    /// Returns the current task id, if any.
101    pub fn task_id(&self) -> Option<&'static str> {
102        self.current_task_index
103            .and_then(|idx| self.task_ids.get(idx).copied())
104    }
105}
106
107/// Builder for [`CuContext`].
108#[derive(Clone, Debug)]
109pub struct CuContextBuilder {
110    clock: RobotClock,
111    cl_id: u64,
112    task_ids: &'static [&'static str],
113}
114
115impl CuContextBuilder {
116    /// Sets the copper-list id for the context.
117    pub fn cl_id(mut self, cl_id: u64) -> Self {
118        self.cl_id = cl_id;
119        self
120    }
121
122    /// Sets the static task id table for task metadata access.
123    pub fn task_ids(mut self, task_ids: &'static [&'static str]) -> Self {
124        self.task_ids = task_ids;
125        self
126    }
127
128    /// Builds a context value.
129    pub fn build(self) -> CuContext {
130        CuContext::new(self.clock, self.cl_id, self.task_ids)
131    }
132}
133
134impl Deref for CuContext {
135    type Target = RobotClock;
136
137    fn deref(&self) -> &Self::Target {
138        &self.clock
139    }
140}