cu29_runtime/app.rs
1use crate::curuntime::KeyFrame;
2use cu29_traits::CopperListTuple;
3use cu29_traits::CuResult;
4use cu29_unifiedlog::{SectionStorage, UnifiedLogWrite};
5
6#[cfg(feature = "std")]
7use crate::copperlist::CopperList;
8#[cfg(not(feature = "std"))]
9use alloc::vec::Vec;
10#[cfg(feature = "std")]
11use cu29_clock::RobotClockMock;
12#[cfg(feature = "std")]
13use std::vec::Vec;
14
15#[cfg(not(feature = "std"))]
16mod imp {
17 pub use alloc::string::String;
18}
19
20#[cfg(feature = "std")]
21mod imp {
22 pub use crate::config::CuConfig;
23 pub use crate::simulation::SimOverride;
24 pub use cu29_clock::RobotClock;
25 pub use cu29_unifiedlog::memmap::MmapSectionStorage;
26 pub use std::sync::{Arc, Mutex};
27}
28
29use imp::*;
30
31/// Convenience trait for CuApplication when it is just a std App
32#[cfg(feature = "std")]
33pub trait CuStdApplication:
34 CuApplication<MmapSectionStorage, cu29_unifiedlog::UnifiedLoggerWrite>
35{
36}
37
38#[cfg(feature = "std")]
39impl<T> CuStdApplication for T where
40 T: CuApplication<MmapSectionStorage, cu29_unifiedlog::UnifiedLoggerWrite>
41{
42}
43
44/// Compile-time subsystem identity embedded in generated Copper applications.
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub struct Subsystem {
47 id: Option<&'static str>,
48 code: u16,
49}
50
51impl Subsystem {
52 #[inline]
53 pub const fn new(id: Option<&'static str>, code: u16) -> Self {
54 Self { id, code }
55 }
56
57 #[inline]
58 pub const fn id(self) -> Option<&'static str> {
59 self.id
60 }
61
62 #[inline]
63 pub const fn code(self) -> u16 {
64 self.code
65 }
66}
67
68/// Compile-time subsystem identity embedded in generated Copper applications.
69pub trait CuSubsystemMetadata {
70 /// Multi-Copper subsystem identity for this generated application.
71 fn subsystem() -> Subsystem;
72}
73
74/// A trait that defines the structure and behavior of a CuApplication.
75///
76/// CuApplication is the normal, running on robot version of an application and its runtime.
77///
78/// The `CuApplication` trait outlines the necessary functions required for managing an application lifecycle,
79/// including configuration management, initialization, task execution, and runtime control. It is meant to be
80/// implemented by types that represent specific applications, providing them with unified control and execution features.
81///
82/// This is the more generic version that allows you to specify a custom unified logger.
83pub trait CuApplication<S: SectionStorage, L: UnifiedLogWrite<S> + 'static> {
84 /// Returns the original configuration as a string, typically loaded from a RON file.
85 /// This configuration represents the default settings for the application before any overrides.
86 fn get_original_config() -> String;
87
88 /// Starts all tasks managed by the application/runtime.
89 ///
90 /// # Returns
91 /// * `Ok(())` - If all tasks are started successfully.
92 /// * `Err(CuResult)` - If an error occurs while attempting to start one
93 /// or more tasks.
94 fn start_all_tasks(&mut self) -> CuResult<()>;
95
96 /// Executes a single iteration of copper-generated runtime (generating and logging one copperlist)
97 ///
98 /// # Returns
99 ///
100 /// * `CuResult<()>` - Returns `Ok(())` if the iteration completes successfully, or an error
101 /// wrapped in `CuResult` if something goes wrong during execution.
102 ///
103 fn run_one_iteration(&mut self) -> CuResult<()>;
104
105 /// Runs indefinitely looping over run_one_iteration
106 ///
107 /// # Returns
108 ///
109 /// Returns a `CuResult<()>`, which indicates the success or failure of the
110 /// operation.
111 /// - On success, the result is `Ok(())`.
112 /// - On failure, an appropriate error wrapped in `CuResult` is returned.
113 fn run(&mut self) -> CuResult<()>;
114
115 /// Stops all tasks managed by the application/runtime.
116 ///
117 /// # Returns
118 ///
119 /// Returns a `CuResult<()>`, which indicates the success or failure of the
120 /// operation.
121 /// - On success, the result is `Ok(())`.
122 /// - On failure, an appropriate error wrapped in `CuResult` is returned.
123 ///
124 fn stop_all_tasks(&mut self) -> CuResult<()>;
125
126 /// Restore all tasks from the given frozen state
127 fn restore_keyframe(&mut self, freezer: &KeyFrame) -> CuResult<()>;
128}
129
130/// A trait that defines the structure and behavior of a simulation-enabled CuApplication.
131///
132/// CuSimApplication is the simulation version of an application and its runtime, allowing
133/// overriding of steps with simulated behavior.
134///
135/// The `CuSimApplication` trait outlines the necessary functions required for managing an application lifecycle
136/// in simulation mode, including configuration management, initialization, task execution, and runtime control.
137#[cfg(feature = "std")]
138pub trait CuSimApplication<S: SectionStorage, L: UnifiedLogWrite<S> + 'static> {
139 /// The type representing a simulation step that can be overridden
140 type Step<'z>;
141
142 /// Returns the original configuration as a string, typically loaded from a RON file.
143 /// This configuration represents the default settings for the application before any overrides.
144 fn get_original_config() -> String;
145
146 /// Returns the mission id this generated application is bound to, when applicable.
147 fn mission_id() -> Option<&'static str> {
148 None
149 }
150
151 /// Starts all tasks managed by the application/runtime in simulation mode.
152 ///
153 /// # Arguments
154 /// * `sim_callback` - A mutable function reference that allows overriding individual simulation steps.
155 ///
156 /// # Returns
157 /// * `Ok(())` - If all tasks are started successfully.
158 /// * `Err(CuResult)` - If an error occurs while attempting to start one
159 /// or more tasks.
160 fn start_all_tasks(
161 &mut self,
162 sim_callback: &mut impl for<'z> FnMut(Self::Step<'z>) -> SimOverride,
163 ) -> CuResult<()>;
164
165 /// Executes a single iteration of copper-generated runtime in simulation mode.
166 ///
167 /// # Arguments
168 /// * `sim_callback` - A mutable function reference that allows overriding individual simulation steps.
169 ///
170 /// # Returns
171 ///
172 /// * `CuResult<()>` - Returns `Ok(())` if the iteration completes successfully, or an error
173 /// wrapped in `CuResult` if something goes wrong during execution.
174 fn run_one_iteration(
175 &mut self,
176 sim_callback: &mut impl for<'z> FnMut(Self::Step<'z>) -> SimOverride,
177 ) -> CuResult<()>;
178
179 /// Runs indefinitely looping over run_one_iteration in simulation mode
180 ///
181 /// # Arguments
182 /// * `sim_callback` - A mutable function reference that allows overriding individual simulation steps.
183 ///
184 /// # Returns
185 ///
186 /// Returns a `CuResult<()>`, which indicates the success or failure of the
187 /// operation.
188 /// - On success, the result is `Ok(())`.
189 /// - On failure, an appropriate error wrapped in `CuResult` is returned.
190 fn run(
191 &mut self,
192 sim_callback: &mut impl for<'z> FnMut(Self::Step<'z>) -> SimOverride,
193 ) -> CuResult<()>;
194
195 /// Stops all tasks managed by the application/runtime in simulation mode.
196 ///
197 /// # Arguments
198 /// * `sim_callback` - A mutable function reference that allows overriding individual simulation steps.
199 ///
200 /// # Returns
201 ///
202 /// Returns a `CuResult<()>`, which indicates the success or failure of the
203 /// operation.
204 /// - On success, the result is `Ok(())`.
205 /// - On failure, an appropriate error wrapped in `CuResult` is returned.
206 fn stop_all_tasks(
207 &mut self,
208 sim_callback: &mut impl for<'z> FnMut(Self::Step<'z>) -> SimOverride,
209 ) -> CuResult<()>;
210
211 /// Restore all tasks from the given frozen state
212 fn restore_keyframe(&mut self, freezer: &KeyFrame) -> CuResult<()>;
213}
214
215/// Optional introspection hook exposing the latest runtime-generated CopperList snapshot.
216///
217/// This is remote-debug-only: debugger conveniences must not add unconditional
218/// runtime-path overhead to normal Copper builds. Non-`remote-debug` builds
219/// should implement this as a cheap `None`.
220pub trait CurrentRuntimeCopperList<P: CopperListTuple> {
221 fn current_runtime_copperlist_bytes(&self) -> Option<&[u8]>;
222
223 fn set_current_runtime_copperlist_bytes(&mut self, snapshot: Option<Vec<u8>>) {
224 let _ = snapshot;
225 }
226}
227
228/// Simulation-enabled applications that can replay a recorded CopperList verbatim.
229///
230/// This is the exact-output replay primitive used by deterministic re-sim flows:
231/// task outputs and bridge receives are overridden from the recorded CopperList,
232/// bridge sends are skipped, and an optional recorded keyframe can be injected
233/// verbatim when the current CL is expected to capture one.
234#[cfg(feature = "std")]
235pub trait CuRecordedReplayApplication<S: SectionStorage, L: UnifiedLogWrite<S> + 'static>:
236 CuSimApplication<S, L>
237{
238 /// The generated recorded CopperList payload set for this application.
239 type RecordedDataSet: CopperListTuple;
240
241 /// Replay one recorded CopperList exactly as logged.
242 fn replay_recorded_copperlist(
243 &mut self,
244 clock_mock: &RobotClockMock,
245 copperlist: &CopperList<Self::RecordedDataSet>,
246 keyframe: Option<&KeyFrame>,
247 ) -> CuResult<()>;
248}
249
250/// Simulation-enabled applications that can be instantiated for distributed replay.
251///
252/// This extends exact-output replay with the one extra capability the
253/// distributed engine needs: build a replayable app for a specific
254/// deployment `instance_id` while keeping app construction type-safe.
255#[cfg(feature = "std")]
256pub trait CuDistributedReplayApplication<S: SectionStorage, L: UnifiedLogWrite<S> + 'static>:
257 CuRecordedReplayApplication<S, L> + CuSubsystemMetadata
258{
259 /// Build this app for deterministic distributed replay.
260 fn build_distributed_replay(
261 clock: RobotClock,
262 unified_logger: Arc<Mutex<L>>,
263 instance_id: u32,
264 config_override: Option<CuConfig>,
265 ) -> CuResult<Self>
266 where
267 Self: Sized;
268}