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