1#![cfg_attr(not(feature = "std"), no_std)]
65#[cfg(all(feature = "parallel-rt", not(feature = "std")))]
66compile_error!("feature `parallel-rt` requires `std`");
67#[cfg(not(feature = "std"))]
68extern crate alloc;
69extern crate self as cu29;
70
71pub use cu29_derive::{bundle_resources, resources, safety_case};
72pub use cu29_runtime::app;
73pub use cu29_runtime::config;
74pub use cu29_runtime::context;
75pub use cu29_runtime::copperlist;
76#[cfg(feature = "std")]
77pub use cu29_runtime::cuasynctask;
78pub use cu29_runtime::cubridge;
79pub use cu29_runtime::curuntime;
80pub use cu29_runtime::cutask;
81#[cfg(feature = "std")]
82pub use cu29_runtime::debug;
83#[cfg(feature = "std")]
84pub use cu29_runtime::distributed_replay;
85pub use cu29_runtime::input_msg;
86pub use cu29_runtime::logcodec;
87pub use cu29_runtime::monitoring;
88pub use cu29_runtime::output_msg;
89#[cfg(all(feature = "std", feature = "parallel-rt"))]
90pub use cu29_runtime::parallel_queue;
91#[cfg(all(feature = "std", feature = "parallel-rt"))]
92pub use cu29_runtime::parallel_rt;
93pub use cu29_runtime::payload;
94pub use cu29_runtime::reflect;
95pub use cu29_runtime::reflect as bevy_reflect;
96#[cfg(feature = "remote-debug")]
97pub use cu29_runtime::remote_debug;
98#[cfg(feature = "std")]
99pub use cu29_runtime::replay;
100pub use cu29_runtime::resource;
101pub use cu29_runtime::rx_channels;
102#[cfg(feature = "std")]
103pub use cu29_runtime::simulation;
104pub use cu29_runtime::tx_channels;
105#[cfg(feature = "safety-ids")]
106pub mod safety;
107#[cfg(all(feature = "std", any(test, feature = "safety-ids")))]
108mod safety_runtime_cases;
109
110#[cfg(feature = "safety-ids")]
111#[doc(hidden)]
112pub fn link_safety_ids() {
113 safety_runtime_cases::link_safety_ids();
114}
115
116#[cfg(feature = "rtsan")]
117pub mod rtsan {
118 pub use rtsan_standalone::*;
119}
120
121#[cfg(not(feature = "rtsan"))]
122pub mod rtsan {
123 use core::ffi::CStr;
124
125 #[derive(Default)]
126 pub struct ScopedSanitizeRealtime;
127
128 #[derive(Default)]
129 pub struct ScopedDisabler;
130
131 #[inline]
132 pub fn realtime_enter() {}
133
134 #[inline]
135 pub fn realtime_exit() {}
136
137 #[inline]
138 pub fn disable() {}
139
140 #[inline]
141 pub fn enable() {}
142
143 #[inline]
144 pub fn ensure_initialized() {}
145
146 #[allow(unused_variables)]
147 pub fn notify_blocking_call(_function_name: &'static CStr) {}
148}
149
150pub use bincode;
151pub use cu29_clock as clock;
152#[cfg(feature = "units")]
153pub use cu29_units as units;
154#[doc(hidden)]
155pub use serde;
156#[cfg(feature = "defmt")]
157pub mod defmt {
158 pub use defmt::{debug, error, info, warn};
159}
160#[cfg(feature = "std")]
161pub use cu29_runtime::config::read_configuration;
162#[cfg(feature = "std")]
163pub use cu29_runtime::config::read_multi_configuration;
164pub use cu29_traits::*;
165
166#[cfg(feature = "std")]
167pub use rayon;
168
169#[doc(hidden)]
170pub mod __private {
171 #[doc(hidden)]
172 pub mod sync {
173 #[cfg(not(feature = "std"))]
174 pub use alloc::sync::Arc;
175 #[cfg(not(feature = "std"))]
176 pub use spin::Mutex;
177 #[cfg(feature = "std")]
178 pub use std::sync::{Arc, Mutex};
179 }
180}
181
182#[cfg(all(feature = "defmt", not(feature = "std")))]
184#[macro_export]
185macro_rules! defmt_debug {
186 ($fmt:literal $(, $arg:expr)* $(,)?) => {
187 $crate::defmt::debug!($fmt $(, $arg)*);
188 }
189}
190#[cfg(not(all(feature = "defmt", not(feature = "std"))))]
191#[macro_export]
192macro_rules! defmt_debug {
193 ($($tt:tt)*) => {{}};
194}
195
196#[cfg(all(feature = "defmt", not(feature = "std")))]
197#[macro_export]
198macro_rules! defmt_info {
199 ($fmt:literal $(, $arg:expr)* $(,)?) => {
200 $crate::defmt::info!($fmt $(, $arg)*);
201 }
202}
203#[cfg(not(all(feature = "defmt", not(feature = "std"))))]
204#[macro_export]
205macro_rules! defmt_info {
206 ($($tt:tt)*) => {{}};
207}
208
209#[cfg(all(feature = "defmt", not(feature = "std")))]
210#[macro_export]
211macro_rules! defmt_warn {
212 ($fmt:literal $(, $arg:expr)* $(,)?) => {
213 $crate::defmt::warn!($fmt $(, $arg)*);
214 }
215}
216#[cfg(not(all(feature = "defmt", not(feature = "std"))))]
217#[macro_export]
218macro_rules! defmt_warn {
219 ($($tt:tt)*) => {{}};
220}
221
222#[cfg(all(feature = "defmt", not(feature = "std")))]
223#[macro_export]
224macro_rules! defmt_error {
225 ($fmt:literal $(, $arg:expr)* $(,)?) => {
226 $crate::defmt::error!($fmt $(, $arg)*);
227 }
228}
229#[cfg(not(all(feature = "defmt", not(feature = "std"))))]
230#[macro_export]
231macro_rules! defmt_error {
232 ($($tt:tt)*) => {{}};
233}
234
235#[macro_export]
236macro_rules! safety_check {
237 ($check_id:literal, $requirement_id:literal, $condition:expr $(,)?) => {
238 assert!(
239 $condition,
240 "safety check {} for requirement {} failed",
241 $check_id, $requirement_id
242 );
243 };
244}
245
246#[macro_export]
247macro_rules! safety_check_eq {
248 ($check_id:literal, $requirement_id:literal, $left:expr, $right:expr $(,)?) => {
249 assert_eq!(
250 $left, $right,
251 "safety check {} for requirement {} failed",
252 $check_id, $requirement_id
253 );
254 };
255}
256
257pub mod prelude {
263 pub use crate::bevy_reflect;
264 #[cfg(feature = "units")]
265 pub use crate::units;
266 pub use crate::{defmt_debug, defmt_error, defmt_info, defmt_warn};
267 pub use crate::{safety_case, safety_check, safety_check_eq};
268 #[cfg(feature = "reflect")]
269 pub use bevy_reflect_derive::Reflect;
270 #[cfg(feature = "signal-handler")]
271 pub use ctrlc;
272 pub use cu29_clock::*;
273 pub use cu29_derive::*;
274 pub use cu29_log::*;
275 pub use cu29_log_derive::*;
276 pub use cu29_log_runtime::*;
277 #[cfg(not(feature = "reflect"))]
278 pub use cu29_reflect_derive::Reflect;
279 pub use cu29_runtime::app;
280 pub use cu29_runtime::app::*;
281 pub use cu29_runtime::config::*;
282 pub use cu29_runtime::context::*;
283 pub use cu29_runtime::copperlist::*;
284 pub use cu29_runtime::cubridge::*;
285 pub use cu29_runtime::curuntime::{
286 CuRuntime, KeyFrame, RuntimeLifecycleConfigSource, RuntimeLifecycleEvent,
287 RuntimeLifecycleRecord, RuntimeLifecycleStackInfo,
288 };
289 pub use cu29_runtime::cutask::*;
290 #[cfg(feature = "std")]
291 pub use cu29_runtime::debug::*;
292 pub use cu29_runtime::input_msg;
293 pub use cu29_runtime::monitoring::*;
294 pub use cu29_runtime::output_msg;
295 pub use cu29_runtime::payload::*;
296 #[cfg(feature = "std")]
297 pub use cu29_runtime::pool::*;
298 #[cfg(feature = "reflect")]
299 pub use cu29_runtime::reflect::serde as reflect_serde;
300 #[cfg(feature = "reflect")]
301 pub use cu29_runtime::reflect::serde::{
302 ReflectSerializer, SerializationData, TypedReflectSerializer,
303 };
304 pub use cu29_runtime::reflect::{
305 GetTypeRegistration, ReflectTaskIntrospection, ReflectTypePath, TypeInfo, TypePath,
306 TypeRegistry, dump_type_registry_schema,
307 };
308 pub use cu29_runtime::resource::*;
309 pub use cu29_runtime::rx_channels;
310 #[cfg(feature = "std")]
311 pub use cu29_runtime::simulation::*;
312 pub use cu29_runtime::tx_channels;
313 pub use cu29_traits::{
314 COMPACT_STRING_CAPACITY, CopperListTuple, CuCompactString, CuError, CuMsgMetadataTrait,
315 CuMsgOrigin, CuPayloadRawBytes, CuResult, DebugFieldDescriptor, DebugFieldKind,
316 DebugFieldSemantics, DebugScalarRegistration, DebugScalarType, ErasedCuStampedData,
317 ErasedCuStampedDataSet, MatchingTasks, Metadata, ObservedWriter, PayloadSchemas,
318 TaskOutputSpec, UnifiedLogType, WriteStream, abort_observed_encode, begin_observed_encode,
319 finish_observed_encode, observed_encode_bytes, record_observed_encode_bytes, with_cause,
320 };
321 #[cfg(feature = "std")]
322 pub use cu29_unifiedlog::memmap;
323 pub use cu29_unifiedlog::*;
324 pub use cu29_value::Value;
325 pub use cu29_value::to_value;
326 pub use serde_derive::{Deserialize, Serialize};
327}
328
329#[cfg(all(test, feature = "std"))]
330mod tests {
331 use super::prelude::*;
332 use std::sync::{Arc, Mutex, OnceLock};
333
334 #[derive(Debug)]
335 struct CaptureStream;
336
337 impl WriteStream<CuLogEntry> for CaptureStream {
338 fn log(&mut self, _obj: &CuLogEntry) -> CuResult<()> {
339 Ok(())
340 }
341 }
342
343 fn logger_test_lock() -> std::sync::MutexGuard<'static, ()> {
344 static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
345 LOCK.get_or_init(|| Mutex::new(()))
346 .lock()
347 .unwrap_or_else(|poison| poison.into_inner())
348 }
349
350 fn capture_one_log<F>(emit: F) -> CuLogEntry
351 where
352 F: FnOnce(),
353 {
354 let _guard = logger_test_lock();
355 let runtime = LoggerRuntime::init(RobotClock::default(), CaptureStream, None::<NullLog>);
356 let captured = Arc::new(Mutex::new(Vec::new()));
357 let sink = captured.clone();
358 register_live_log_listener(move |entry, _, _| {
359 sink.lock()
360 .unwrap_or_else(|poison| poison.into_inner())
361 .push(entry.clone());
362 });
363
364 emit();
365
366 unregister_live_log_listener();
367 drop(runtime);
368
369 let entries = captured.lock().unwrap_or_else(|poison| poison.into_inner());
370 assert_eq!(entries.len(), 1, "expected exactly one captured log entry");
371 entries[0].clone()
372 }
373
374 #[test]
375 fn explicit_context_logs_capture_task_origin() {
376 let mut ctx = CuContext::builder(RobotClock::default())
377 .cl_id(77)
378 .task_ids(&["task-0"])
379 .build();
380 ctx.set_current_task(0);
381
382 let entry = capture_one_log(|| {
383 debug!(ctx, "task log {}", 7);
384 });
385
386 assert_eq!(entry.origin.culistid, Some(77));
387 assert_eq!(entry.origin.component_id, Some(0));
388 assert_eq!(entry.origin.task_index, Some(0));
389 }
390
391 #[test]
392 fn explicit_context_logs_capture_bridge_component_origin() {
393 let mut ctx = CuContext::builder(RobotClock::default()).cl_id(88).build();
394 ctx.set_current_component(5);
395 ctx.clear_current_task();
396
397 let entry = capture_one_log(|| {
398 info!(ctx, "bridge log {}", 3);
399 });
400
401 assert_eq!(entry.origin.culistid, Some(88));
402 assert_eq!(entry.origin.component_id, Some(5));
403 assert_eq!(entry.origin.task_index, None);
404 }
405
406 #[test]
407 fn context_free_logs_leave_origin_empty() {
408 let entry = capture_one_log(|| {
409 warning!("context free {}", 1);
410 });
411
412 assert_eq!(entry.origin, CuLogOrigin::default());
413 }
414}