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