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