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