1#![doc = include_str!("../README.md")]
2use core::convert::Infallible;
3use core::mem::size_of;
4use core::ops::DerefMut;
5use core::result::Result;
6use std::io::StdoutLock;
7use std::io::Write;
8use std::sync::MutexGuard;
9
10cfg_if::cfg_if!(
11 if #[cfg(feature="ptr_u128")] {
12 pub type PointerT = u128;
13 } else if #[cfg(feature="ptr_u64")] {
14 pub type PointerT = u64;
15 } else if #[cfg(feature="ptr_u32")] {
16 pub type PointerT = u32;
17 } else if #[cfg(feature="ptr_u16")] {
18 pub type PointerT = u16;
19 } else if #[cfg(feature="ptr_u8")] {
20 pub type PointerT = u8;
21 } else {
22 pub type PointerT = u128;
23 }
24);
25
26cfg_if::cfg_if!(
27 if #[cfg(feature="size_u128")] {
28 pub type SizeT = u128;
29 } else if #[cfg(feature="size_u64")] {
30 pub type SizeT = u64;
31 } else if #[cfg(feature="size_u32")] {
32 pub type SizeT = u32;
33 } else if #[cfg(feature="size_u16")] {
34 pub type SizeT = u16;
35 } else if #[cfg(feature="size_u8")] {
36 pub type SizeT = u8;
37 } else {
38 pub type SizeT = u128;
39 }
40);
41
42cfg_if::cfg_if!(
43 if #[cfg(feature="alignment_power_0")] {
44 pub const ALIGNMENT_POWER: u8 = 0;
45 macro_rules! format_info_repr {
46 ($struct:item) => {
47 #[repr(align(1), C)]
48 $struct
49 }
50 }
51 } else if #[cfg(feature="alignment_power_1")] {
52 pub const ALIGNMENT_POWER: u8 = 1;
53 macro_rules! format_info_repr {
54 ($struct:item) => {
55 #[repr(align(2), C)]
56 $struct
57 }
58 }
59 } else if #[cfg(feature="alignment_power_2")] {
60 pub const ALIGNMENT_POWER: u8 = 2;
61 macro_rules! format_info_repr {
62 ($struct:item) => {
63 #[repr(align(4), C)]
64 $struct
65 }
66 }
67 } else if #[cfg(feature="alignment_power_3")] {
68 pub const ALIGNMENT_POWER: u8 = 3;
69 macro_rules! format_info_repr {
70 ($struct:item) => {
71 #[repr(align(8), C)]
72 $struct
73 }
74 }
75 } else if #[cfg(feature="alignment_power_4")] {
76 pub const ALIGNMENT_POWER: u8 = 4;
77 macro_rules! format_info_repr {
78 ($struct:item) => {
79 #[repr(align(16), C)]
80 $struct
81 }
82 }
83 } else if #[cfg(feature="alignment_power_5")] {
84 pub const ALIGNMENT_POWER: u8 = 5;
85 macro_rules! format_info_repr {
86 ($struct:item) => {
87 #[repr(align(32), C)]
88 $struct
89 }
90 }
91 } else if #[cfg(feature="alignment_power_6")] {
92 pub const ALIGNMENT_POWER: u8 = 6;
93 macro_rules! format_info_repr {
94 ($struct:item) => {
95 #[repr(align(64), C)]
96 $struct
97 }
98 }
99 } else if #[cfg(feature="alignment_power_7")] {
100 pub const ALIGNMENT_POWER: u8 = 7;
101 macro_rules! format_info_repr {
102 ($struct:item) => {
103 #[repr(align(128), C)]
104 $struct
105 }
106 }
107 } else if #[cfg(feature="alignment_power_8")] {
108 pub const ALIGNMENT_POWER: u8 = 8;
109 macro_rules! format_info_repr {
110 ($struct:item) => {
111 #[repr(align(256), C)]
112 $struct
113 }
114 }
115 } else if #[cfg(feature="alignment_power_9")] {
116 pub const ALIGNMENT_POWER: u8 = 9;
117 macro_rules! format_info_repr {
118 ($struct:item) => {
119 #[repr(align(512), C)]
120 $struct
121 }
122 }
123 } else if #[cfg(feature="alignment_power_10")] {
124 pub const ALIGNMENT_POWER: u8 = 10;
125 macro_rules! format_info_repr {
126 ($struct:item) => {
127 #[repr(align(1024), C)]
128 $struct
129 }
130 }
131 } else {
132 pub const ALIGNMENT_POWER: u8 = 6;
133 macro_rules! format_info_repr {
134 ($struct:item) => {
135 #[repr(align(64), C)]
136 $struct
137 }
138 }
139 }
140);
141
142format_info_repr! {
143 pub struct FormatInfo<const LEN: usize> {
144 pub bytes: [u8; LEN],
145 }
146}
147
148#[derive(Copy, Clone)]
149pub enum Size {
150 Static(usize),
151 NullTerminated,
152 LengthPrefixed,
153}
154
155impl Size {
156 pub const fn bytes(&self) -> [u8; size_of::<SizeT>()] {
157 match self {
158 Self::NullTerminated => NULL_TERMINATED.to_ne_bytes(),
159 Self::LengthPrefixed => LENGTH_PREFIXED.to_ne_bytes(),
160 Self::Static(size) => (*size as SizeT).to_ne_bytes(),
161 }
162 }
163}
164
165pub const NULL_TERMINATED: SizeT = 1 << (SizeT::BITS - 1);
166pub const LENGTH_PREFIXED: SizeT = 1 << (SizeT::BITS - 2);
167pub const PY_FORMAT: SizeT = 0;
168pub const NO_FORMAT: SizeT = 1;
169pub const C_STYLE_FORMAT: SizeT = 2;
170
171pub trait Sink {
173 type OutError;
176 type BeginError;
179 fn out(&mut self, b: &[u8]) -> Result<(), Self::OutError>;
181 fn begin(&mut self, info_addr: PointerT, total_size: SizeT) -> Result<(), Self::BeginError>;
191}
192
193pub fn init<T: Sink>(sink: &mut T) -> Result<(), T::OutError> {
196 magic_address_bytes().serialize(sink)
197}
198
199impl<T: Sink> Sink for MutexGuard<'_, T> {
200 type OutError = T::OutError;
201 type BeginError = T::BeginError;
202 fn out(&mut self, b: &[u8]) -> Result<(), Self::OutError> {
203 self.deref_mut().out(b)
204 }
205 fn begin(&mut self, info_addr: PointerT, total_size: SizeT) -> Result<(), Self::BeginError> {
206 self.deref_mut().begin(info_addr, total_size)
207 }
208}
209
210impl Sink for StdoutLock<'_> {
211 type OutError = std::io::Error;
212 type BeginError = Infallible;
213 fn out(&mut self, b: &[u8]) -> Result<(), Self::OutError> {
214 self.write_all(b)?;
215 Ok(())
216 }
217 fn begin(&mut self, _info_addr: PointerT, _total_size: SizeT) -> Result<(), Self::BeginError> {
218 Ok(())
219 }
220}
221
222impl Sink for Vec<u8> {
223 type OutError = Infallible;
224 type BeginError = Infallible;
225 fn out(&mut self, b: &[u8]) -> Result<(), Self::OutError> {
226 self.extend_from_slice(b);
227 Ok(())
228 }
229 fn begin(&mut self, _info_addr: PointerT, total_size: SizeT) -> Result<(), Self::BeginError> {
230 let total_size = total_size & !(NULL_TERMINATED | LENGTH_PREFIXED);
231 self.reserve(total_size as usize);
232 Ok(())
233 }
234}
235
236pub const DESCENDANTS_LIMIT: usize = 0x1000;
237
238pub trait Trace {
239 const SIZE: Size;
240 const ID: &'static str;
241 const NUM_CHILDREN: usize;
242 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)];
243 const NUM_OFFSET_TABLE_ENTRIES: usize = {
245 let mut n = 0;
246 n += 2;
248 n += 1;
250
251 let mut i = 0;
252 let mut remaining = Self::NUM_CHILDREN;
253
254 while remaining > 0 {
256 let descendant = Self::DESCENDANTS[i];
257
258 n += 2;
260 n += 2;
262
263 remaining += descendant.3;
264 remaining -= 1;
265 i += 1;
266 }
267
268 n
269 };
270
271 const INFO_SIZE: usize = {
273 let mut size = 0;
274 size += Self::ID.len() + size_of::<u8>();
276
277 let mut i = 0;
278 let mut remaining = Self::NUM_CHILDREN;
279
280 while remaining > 0 {
282 let descendant = Self::DESCENDANTS[i];
283
284 size += descendant.0.len() + size_of::<u8>();
286 size += descendant.1.len() + size_of::<u8>();
288
289 remaining += descendant.3;
290 remaining -= 1;
291 i += 1;
292 }
293
294 size
295 };
296 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError>;
297 fn size(&self) -> usize;
298}
299
300impl<T> Trace for &T
301where
302 T: Trace,
303 T: ?Sized,
304{
305 const SIZE: Size = T::SIZE;
306 const ID: &'static str = T::ID;
307 const NUM_CHILDREN: usize = T::NUM_CHILDREN;
308 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = T::DESCENDANTS;
309 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
310 (*self).serialize(f)
311 }
312 fn size(&self) -> usize {
313 (*self).size()
314 }
315}
316
317impl<T: Trace> Trace for Box<T> {
318 const SIZE: Size = T::SIZE;
319 const ID: &'static str = T::ID;
320 const NUM_CHILDREN: usize = T::NUM_CHILDREN;
321 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = T::DESCENDANTS;
322 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
323 self.as_ref().serialize(f)
324 }
325 fn size(&self) -> usize {
326 self.as_ref().size()
327 }
328}
329
330impl Trace for str {
331 const SIZE: Size = Size::NullTerminated;
332 const ID: &'static str = "string";
333 const NUM_CHILDREN: usize = 0;
334 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = &[];
335 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
336 f.out(self.as_bytes())
337 }
338 fn size(&self) -> usize {
339 self.len()
340 }
341}
342
343impl Trace for String {
344 const SIZE: Size = str::SIZE;
345 const ID: &'static str = str::ID;
346 const NUM_CHILDREN: usize = str::NUM_CHILDREN;
347 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = str::DESCENDANTS;
348 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
349 self.as_str().serialize(f)
350 }
351 fn size(&self) -> usize {
352 self.as_str().size()
353 }
354}
355
356impl<T: Trace> Trace for [T] {
357 const SIZE: Size = Size::LengthPrefixed;
358 const ID: &'static str = "list";
359 const NUM_CHILDREN: usize = 1;
360 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = &{
361 let mut children = [("", T::ID, T::SIZE, T::NUM_CHILDREN); DESCENDANTS_LIMIT];
362
363 let mut remaining = T::NUM_CHILDREN;
364 let mut i = 0;
365 while remaining > 0 {
366 children[i + Self::NUM_CHILDREN] = T::DESCENDANTS[remaining];
367 remaining += T::DESCENDANTS[remaining].3;
368 remaining -= 1;
369 i += 1;
370 }
371
372 children
373 };
374 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
375 for el in self {
376 if matches!(T::SIZE, Size::LengthPrefixed) {
377 (el.size() as SizeT).serialize(f)?;
378 }
379 el.serialize(f)?;
380 if matches!(T::SIZE, Size::NullTerminated) {
381 0u8.serialize(f)?;
382 }
383 }
384 Ok(())
385 }
386 fn size(&self) -> usize {
387 self.len()
388 }
389}
390
391impl<T: Trace> Trace for Vec<T> {
392 const SIZE: Size = <[T] as Trace>::SIZE;
393 const ID: &'static str = <[T] as Trace>::ID;
394 const NUM_CHILDREN: usize = <[T] as Trace>::NUM_CHILDREN;
395 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] =
396 <[T] as Trace>::DESCENDANTS;
397 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
398 self[..].serialize(f)
399 }
400 fn size(&self) -> usize {
401 self[..].size()
402 }
403}
404
405impl<T: Trace, const N: usize> Trace for [T; N] {
406 const SIZE: Size = Size::Static(N);
407 const ID: &'static str = "list";
408 const NUM_CHILDREN: usize = 1;
409 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] =
410 <[T] as Trace>::DESCENDANTS;
411
412 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
413 for el in self {
414 if matches!(T::SIZE, Size::LengthPrefixed) {
415 (el.size() as SizeT).serialize(f)?;
416 }
417 el.serialize(f)?;
418 if matches!(T::SIZE, Size::NullTerminated) {
419 0u8.serialize(f)?;
420 }
421 }
422 Ok(())
423 }
424
425 fn size(&self) -> usize {
426 N
427 }
428}
429
430macro_rules! impl_trace_for_primitive {
431 ($type:ty, $id:expr) => {
432 impl Trace for $type {
433 const SIZE: Size = Size::Static(std::mem::size_of::<Self>());
434 const ID: &'static str = $id;
435 const NUM_CHILDREN: usize = 0;
436 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = &[];
437
438 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
439 f.out(&self.to_ne_bytes())
440 }
441
442 fn size(&self) -> usize {
443 std::mem::size_of::<Self>()
444 }
445 }
446 };
447}
448
449impl_trace_for_primitive!(i8, "signed char");
450impl_trace_for_primitive!(i16, "signed");
451impl_trace_for_primitive!(i32, "signed");
452impl_trace_for_primitive!(i64, "signed");
453impl_trace_for_primitive!(i128, "signed");
454impl_trace_for_primitive!(isize, "signed");
455
456impl_trace_for_primitive!(u8, "char");
457impl_trace_for_primitive!(u16, "unsigned");
458impl_trace_for_primitive!(u32, "unsigned");
459impl_trace_for_primitive!(u64, "unsigned");
460impl_trace_for_primitive!(u128, "unsigned");
461impl_trace_for_primitive!(usize, "unsigned");
462
463impl_trace_for_primitive!(f32, "float");
464impl_trace_for_primitive!(f64, "double");
465
466impl Trace for bool {
467 const SIZE: Size = Size::Static(std::mem::size_of::<u8>());
468 const ID: &'static str = "bool";
469 const NUM_CHILDREN: usize = 0;
470 const DESCENDANTS: &'static [(&'static str, &'static str, Size, usize)] = &[];
471
472 fn serialize<O: Sink>(&self, f: &mut O) -> Result<(), O::OutError> {
473 f.out(&[*self as u8])
474 }
475
476 fn size(&self) -> usize {
477 std::mem::size_of::<u8>()
478 }
479}
480
481#[derive(Debug)]
482pub enum Error<BeginError, OutError> {
483 Begin(BeginError),
484 Out(OutError),
485}
486
487#[macro_export]
488macro_rules! count {
489 () => (0usize);
490 ( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
491}
492
493#[macro_export]
494macro_rules! sink {
495 () => {
496 std::io::stdout().lock()
497 };
498 (.sink_guard=$sink_guard:expr,) => {
499 $sink_guard
500 };
501 (.sink_guard=$sink_guard:expr, .sink=$sink:expr,) => {{
502 const _: () = assert!(
503 false,
504 "Only one of '.sink', and '.sink_guard' may be specified"
505 );
506 ()
507 }};
508 (.sink=$sink:expr,) => {
509 ()
510 };
511}
512
513#[macro_export]
587macro_rules! trace_impl {
588 ($($fmt:literal)+ $(, $($types:ty : $args:expr),+)? $(, .section = $section:literal)? $(, .sink_guard = $sink_guard:expr)? $(, .sink = $sink:expr)? $(, .error_handler = $error_handler:expr)? $(, .formatter=$formatter:expr)?)
589 =>
590 {
591 {
592 let result = 'trace: {
593 const FMT: &str = core::concat!($($fmt,)+);
594 const NUM_PREFIX: usize = {
595 let mut size = 5;
596 $($(
597 size += <$types as $crate::Trace>::NUM_OFFSET_TABLE_ENTRIES;
598 )*)?
599 size
600 };
601 const INFO_SIZE: usize = {
602 let mut size: usize = 0;
603 $($(
604 size += <$types as $crate::Trace>::INFO_SIZE;
605 )*)?
606 size += NUM_PREFIX * size_of::<$crate::SizeT>() + FMT.as_bytes().len() + file!().as_bytes().len() + 2;
607 size
608 };
609 #[unsafe(link_section = ".emtrace")]
610 $(
611 static _DUMMY: i32 = 0;
612 #[unsafe(link_section = $section)]
613 )?
614 #[used]
615 static FMT_INFO: $crate::FormatInfo<INFO_SIZE> = {
616 let size_t_size = size_of::<$crate::SizeT>();
617 let num_args = ($crate::count!($($($types)*)?)) as $crate::SizeT;
618 let mut offset_idx: usize = 0;
619 let mut data_idx = (NUM_PREFIX * size_t_size) as $crate::SizeT;
620 let mut info = [0; INFO_SIZE];
621
622 let num_args_arr = num_args.to_ne_bytes();
623 let mut i = 0;
624 while i < size_t_size {
625 info[offset_idx] = num_args_arr[i];
626 offset_idx += 1;
627 i += 1;
628 }
629
630 let fmt_offset_arr = data_idx.to_ne_bytes();
631 let mut i = 0;
632 while i < size_t_size {
633 info[offset_idx] = fmt_offset_arr[i];
634 offset_idx += 1;
635 i += 1;
636 }
637
638 let fmt_str_arr = FMT.as_bytes();
639 let mut i = 0;
640 while i < FMT.len() {
641 info[data_idx as usize] = fmt_str_arr[i];
642 data_idx += 1;
643 i += 1;
644 }
645 data_idx += 1;
646
647 ($($(
648 {
649 let id_offset_arr = data_idx.to_ne_bytes();
650 let mut i = 0;
651 while i < size_t_size {
652 info[offset_idx] = id_offset_arr[i];
653 offset_idx += 1;
654 i += 1;
655 }
656
657 let size_arr = <$types as $crate::Trace>::SIZE.bytes();
658 let mut i = 0;
659 while i < size_t_size {
660 info[offset_idx] = size_arr[i];
661 offset_idx += 1;
662 i += 1;
663 }
664
665 let num_children_arr = (<$types as $crate::Trace>::NUM_CHILDREN as $crate::SizeT).to_ne_bytes();
666 let mut i = 0;
667 while i < size_t_size {
668 info[offset_idx] = num_children_arr[i];
669 offset_idx += 1;
670 i += 1;
671 }
672
673 let id_arr = <$types as $crate::Trace>::ID.as_bytes();
674 let mut i = 0;
675 while i < <$types as $crate::Trace>::ID.len() {
676 info[data_idx as usize] = id_arr[i];
677 data_idx += 1;
678 i += 1;
679 }
680 data_idx += 1;
681
682 let mut j = 0;
683 let mut remaining = <$types as $crate::Trace>::NUM_CHILDREN;
684 while remaining > 0 {
685 let descendant = <$types as $crate::Trace>::DESCENDANTS[j];
686
687 let name_offset_arr = data_idx.to_ne_bytes();
688 let mut i = 0;
689 while i < size_t_size {
690 info[offset_idx] = name_offset_arr[i];
691 offset_idx += 1;
692 i += 1;
693 }
694
695 let size_arr = descendant.2.bytes();
696 let mut i = 0;
697 while i < size_t_size {
698 info[offset_idx] = size_arr[i];
699 offset_idx += 1;
700 i += 1;
701 }
702
703 let num_children_arr = (descendant.3 as $crate::SizeT).to_ne_bytes();
704 let mut i = 0;
705 while i < size_t_size {
706 info[offset_idx] = num_children_arr[i];
707 offset_idx += 1;
708 i += 1;
709 }
710
711 let n = descendant.0.len();
712 let name_arr = descendant.0.as_bytes();
713 let mut i = 0;
714 while i < n {
715 info[data_idx as usize] = name_arr[i];
716 data_idx += 1;
717 i += 1;
718 }
719 data_idx += 1;
720
721 let id_offset_arr = data_idx.to_ne_bytes();
722 let mut i = 0;
723 while i < size_t_size {
724 info[offset_idx] = id_offset_arr[i];
725 offset_idx += 1;
726 i += 1;
727 }
728
729 let n = descendant.1.len();
730 let id_arr = descendant.1.as_bytes();
731 let mut i = 0;
732 while i < n {
733 info[data_idx as usize] = id_arr[i];
734 data_idx += 1;
735 i += 1;
736 }
737 data_idx += 1;
738
739 remaining += descendant.3;
740 remaining -= 1;
741 j += 1;
742 }
743
744 }
745 ),*)?);
746
747 let formatter = $crate::NO_FORMAT;
748 $($(
751 let _dummy = formatter;
752 let _dummy = <$types as $crate::Trace>::SIZE;
753 let formatter = $crate::PY_FORMAT;
754 )*)?
755 $(
756 let _dummy = formatter;
757 let formatter = $formatter;
758 )?
759 let formatter_arr = (formatter as $crate::SizeT).to_ne_bytes();
760 let mut i = 0;
761 while i < size_t_size {
762 info[offset_idx] = formatter_arr[i];
763 offset_idx += 1;
764 i += 1;
765 }
766
767 let file_offset_arr = data_idx.to_ne_bytes();
768 let mut i = 0;
769 while i < size_t_size {
770 info[offset_idx] = file_offset_arr[i];
771 offset_idx += 1;
772 i += 1;
773 }
774
775 let file_arr = file!().as_bytes();
776 let mut i = 0;
777 while i < file!().len() {
778 info[data_idx as usize] = file_arr[i];
779 data_idx += 1;
780 i += 1;
781 }
782
783 let line_arr = (line!() as $crate::SizeT).to_ne_bytes();
784 let mut i = 0;
785 while i < size_t_size {
786 info[offset_idx] = line_arr[i];
787 offset_idx += 1;
788 i += 1;
789 }
790
791 $crate::FormatInfo{
792 bytes: info
793 }
794
795 };
796 const TOTAL_SIZE: usize = {
797 let mut total_size = 0usize;
798 $($(
799 total_size += match <$types as $crate::Trace>::SIZE {
800 $crate::Size::NullTerminated |$crate::Size::LengthPrefixed => 0,
801 $crate::Size::Static(size) => size,
802
803 };
804 )*)?
805 total_size += size_of::<$crate::SizeT>();
806
807 total_size
808 };
809
810 use $crate::Sink;
811 #[allow(unused_mut)]
812 let mut sink = $crate::sink!(
813 $(.sink_guard=$sink_guard,)? $(.sink=$sink,)?
814 );
815 let sink_ref = &mut sink;
816 $(
817 let _dummy = sink_ref;
818 #[allow(unused_mut)]
819 let sink_ref = &mut $sink;
820 )?
821 let addr = (FMT_INFO.bytes.as_ptr().addr() >> $crate::ALIGNMENT_POWER) as $crate::PointerT;
822 let result = sink_ref.begin(addr, TOTAL_SIZE as $crate::SizeT);
823 if let Err(err) = result {
824 break 'trace Err($crate::Error::Begin(err));
825 }
826
827 let result = $crate::Trace::serialize(&addr, sink_ref);
828 if let Err(err) = result {
829 break 'trace Err($crate::Error::Out(err));
830 }
831 $($(
832 let x:&$types = &$args;
833 if matches!(<$types as $crate::Trace>::SIZE, $crate::Size::LengthPrefixed) {
834 let result = $crate::Trace::serialize(&($crate::Trace::size(x) as $crate::SizeT), sink_ref);
835 if let Err(err) = result {
836 break 'trace Err($crate::Error::Out(err));
837 }
838 }
839 let result = $crate::Trace::serialize(x, sink_ref);
840 if let Err(err) = result {
841 break 'trace Err($crate::Error::Out(err));
842 }
843 if matches!(<$types as $crate::Trace>::SIZE, $crate::Size::NullTerminated) {
844 let null = 0u8;
845 let result = $crate::Trace::serialize(&null, sink_ref);
846 if let Err(err) = result {
847 break 'trace Err($crate::Error::Out(err));
848 }
849 }
850 )*)?
851 Ok(())
852 };
853 $(
854 let result = $error_handler(result);
855 )?
856 result
857 }
858 }
859}
860
861#[macro_export]
895macro_rules! trace{
896 ($fmt:literal $(, $($types:ty : $args:expr),+)? $(, .section = $section:literal)? $(, .sink_guard = $sink_guard:expr)? $(, .sink= $sink:expr)? $(, .formatter=$formatter:expr)?)
897 => {
898 $crate::trace_impl!($fmt $(, $($types: $args),+)? $(, .section = $section)? $(, .sink_guard = $sink_guard)? $(, .sink= $sink)?, .error_handler=core::result::Result::unwrap $(, .formatter=$formatter)?)
899 };
900 ($fmt:literal $(, $($types:ty : $args:expr),+)? $(, .section = $section:literal)? $(, .sink_guard = $sink_guard:expr)? $(, .sink= $sink:expr)?, .handle_errors $(, .formatter=$formatter:expr)?)
901 => {
902 $crate::trace_impl!($fmt $(, $($types: $args),+)? $(, .section = $section)? $(, .sink_guard = $sink_guard)? $(, .sink= $sink)? $(, .formatter=$formatter)?)
903 };
904}
905
906#[macro_export]
939macro_rules! traceln {
940 ($fmt:literal $(, $($types:ty : $args:expr),+)? $(, .section = $section:literal)? $(, .sink_guard = $sink_guard:expr)? $(, .sink= $sink:expr)? $(, .formatter=$formatter:expr)?)
941 => {
942 $crate::trace_impl!($fmt "\n" $(, $($types: $args),+)? $(, .section = $section)? $(, .sink_guard = $sink_guard)? $(, .sink= $sink)?, .error_handler=core::result::Result::unwrap $(, .formatter=$formatter)?)
943 };
944 ($fmt:literal $(, $($types:ty : $args:expr),+)? $(, .section = $section:literal)? $(, .sink_guard = $sink_guard:expr)? $(, .sink= $sink:expr)?, .handle_errors $(, .formatter=$formatter:expr)?)
945 => {
946 $crate::trace_impl!($fmt "\n" $(, $($types: $args),+)? $(, .section = $section)? $(, .sink_guard = $sink_guard)? $(, .sink= $sink)? $(, .formatter=$formatter)?)
947 };
948}
949
950#[macro_export]
951macro_rules! expect {
952 ($expected:literal, .section=$section:literal) => {
953 {
954 const LEN: usize = $expected.len();
955 #[unsafe(link_section = $section)]
956 #[unsafe(no_mangle)]
957 static EXPECTED_OUTPUT: [u8; LEN] = {
958 let mut bytes: [u8; LEN] = [0; LEN];
959
960 let mut i = 0usize;
961 while i < LEN {
962 bytes[i] = $expected.as_bytes()[i];
963 i += 1;
964 }
965
966 bytes
967 };
968 let _ = unsafe { std::ptr::read_volatile(&EXPECTED_OUTPUT) };
969 }
970 };
971 ($expected:literal) => {
972 expect!($expected, .section=".emtrace.test.expected")
973 };
974}
975const MAGIC_SIZE: usize = 36 + 3 * size_of::<SizeT>();
976
977type Magic = FormatInfo<MAGIC_SIZE>;
978
979#[unsafe(link_section = ".emtrace")]
980#[used]
981pub static EMTRACE_MAGIC: Magic = {
982 let id = [
983 0xd1, 0x97, 0xf5, 0x22, 0xd9, 0x26, 0x9f, 0xd1, 0xad, 0x70, 0x33, 0x92, 0xf6, 0x59, 0xdf,
984 0xd0, 0xfb, 0xec, 0xbd, 0x60, 0x97, 0x13, 0x25, 0xe8, 0x92, 0x01, 0xb2, 0x5a, 0x38, 0x5d,
985 0x9e, 0xc7,
986 ];
987
988 let mut magic = [0; MAGIC_SIZE];
989 let mut i = 0;
990 while i < 32 {
991 magic[i] = id[i];
992 i += 1;
993 }
994 magic[32] = 36;
995 magic[33] = size_of::<SizeT>() as u8;
996 magic[34] = size_of::<PointerT>() as u8;
997 magic[35] = ALIGNMENT_POWER;
998
999 let mut idx = 36;
1000
1001 #[allow(overflowing_literals)]
1002 let byte_order_id_arr = (0x0f0e0d0c0b0a09080706050403020100 as SizeT).to_ne_bytes();
1003 let mut i = 0;
1004 while i < size_of::<SizeT>() {
1005 magic[idx] = byte_order_id_arr[i];
1006 idx += 1;
1007 i += 1;
1008 }
1009
1010 let null_terminated_arr = NULL_TERMINATED.to_ne_bytes();
1011 let mut i = 0;
1012 while i < size_of::<SizeT>() {
1013 magic[idx] = null_terminated_arr[i];
1014 idx += 1;
1015 i += 1;
1016 }
1017
1018 let length_prefixed_arr = LENGTH_PREFIXED.to_ne_bytes();
1019 let mut i = 0;
1020 while i < size_of::<SizeT>() {
1021 magic[idx] = length_prefixed_arr[i];
1022 idx += 1;
1023 i += 1;
1024 }
1025 Magic { bytes: magic }
1026};
1027
1028pub fn magic_address_bytes() -> [u8; size_of::<PointerT>()] {
1029 let raw_address = (&EMTRACE_MAGIC as *const Magic).addr();
1030 ((raw_address >> ALIGNMENT_POWER) as PointerT).to_ne_bytes()
1031}
1032
1033#[cfg(test)]
1034mod tests {
1035 use super::{SizeT, trace};
1036 use std::str::FromStr;
1037
1038 #[test]
1039 fn test() {
1040 let mut capture = Vec::new();
1041 trace!("{}", i32: 32, .sink=capture);
1042 assert_eq!(capture.len(), size_of::<SizeT>() + size_of::<i32>());
1043 let mut arg_bytes: [u8; size_of::<i32>()] = [0; size_of::<i32>()];
1044 arg_bytes
1045 .copy_from_slice(&capture[size_of::<SizeT>()..size_of::<SizeT>() + size_of::<i32>()]);
1046 let arg = i32::from_ne_bytes(arg_bytes);
1047 assert_eq!(arg, 32);
1048 }
1049
1050 #[test]
1051 fn empty_vec() {
1052 let mut capture = Vec::new();
1053 let v = Vec::<i32>::new();
1054 trace!("{}", [i32]: v, .sink=capture);
1055 assert_eq!(capture.len(), size_of::<SizeT>() * 2);
1056 trace!("{}", Vec<i32>: v, .sink=capture);
1057 assert_eq!(capture.len(), size_of::<SizeT>() * 4);
1058 }
1059
1060 #[test]
1061 fn flat_vec() {
1062 let mut capture1 = Vec::new();
1063 let mut capture2 = Vec::new();
1064 let v = vec![1, 3, 4, 6];
1065
1066 let expected_len = 2 * size_of::<SizeT>() + v.len() * size_of::<i32>();
1067 trace!("{}", [i32]: v, .sink=capture1);
1068 assert_eq!(capture1.len(), expected_len);
1069 trace!("{}", Vec<i32>: v, .sink=capture2);
1070 assert_eq!(capture2.len(), expected_len);
1071
1072 assert_eq!(
1073 capture1[size_of::<SizeT>()..],
1074 capture2[size_of::<SizeT>()..]
1075 );
1076 assert_ne!(
1077 capture1[..size_of::<SizeT>()],
1078 capture2[..size_of::<SizeT>()]
1079 );
1080 }
1081
1082 #[test]
1083 fn nested_vecs() {
1084 let mut capture1 = Vec::new();
1085 let mut capture2 = Vec::new();
1086 let mut capture3 = Vec::new();
1087 let mut capture4 = Vec::new();
1088 let owning = vec![vec![1, 2, 3, 4], vec![10]];
1089 let referencing_vec = vec![&owning[0], &owning[1]];
1090 let referencing_slice = vec![&owning[0][..], &owning[1]];
1091
1092 let expected_len = 2 * size_of::<SizeT>()
1093 + owning
1094 .iter()
1095 .map(|inner| inner.len() * size_of::<i32>() + size_of::<SizeT>())
1096 .sum::<usize>();
1097 trace!("{}", Vec<Vec<i32>>: owning, .sink=capture1);
1098 assert_eq!(capture1.len(), expected_len);
1099 trace!("{}", [Vec<i32>]: owning, .sink=capture2);
1100 assert_eq!(capture2.len(), expected_len);
1101 trace!("{}", [&Vec<i32>]: referencing_vec, .sink=capture3);
1102 assert_eq!(capture3.len(), expected_len);
1103 trace!("{}", [&[i32]]: referencing_slice, .sink=capture4);
1104 assert_eq!(capture4.len(), expected_len);
1105
1106 assert_eq!(
1107 capture1[size_of::<SizeT>()..],
1108 capture2[size_of::<SizeT>()..]
1109 );
1110 assert_eq!(
1111 capture1[size_of::<SizeT>()..],
1112 capture3[size_of::<SizeT>()..]
1113 );
1114 assert_eq!(
1115 capture1[size_of::<SizeT>()..],
1116 capture4[size_of::<SizeT>()..]
1117 );
1118 }
1119
1120 #[test]
1121 fn string() {
1122 let mut capture1 = Vec::new();
1123 let mut capture2 = Vec::new();
1124 let mut capture3 = Vec::new();
1125 let literal = "Hello, there!";
1126 let owning = String::from_str(literal).unwrap();
1127
1128 let expected_len = size_of::<SizeT>() + literal.len() + size_of::<u8>();
1129 trace!("{}", str: literal, .sink=capture1);
1130 assert_eq!(capture1.len(), expected_len);
1131 trace!("{}", str: owning, .sink=capture2);
1132 assert_eq!(capture2.len(), expected_len);
1133 trace!("{}", String: owning, .sink=capture3);
1134 assert_eq!(capture3.len(), expected_len);
1135
1136 assert_eq!(
1137 capture1[size_of::<SizeT>()..],
1138 capture2[size_of::<SizeT>()..]
1139 );
1140 assert_eq!(
1141 capture1[size_of::<SizeT>()..],
1142 capture3[size_of::<SizeT>()..]
1143 );
1144 }
1145
1146 #[test]
1147 fn vec_of_string() {
1148 let mut capture1 = Vec::new();
1149 let mut capture2 = Vec::new();
1150 let slices = vec!["A", "vector", "of", "strings"];
1151 let owning = slices
1152 .iter()
1153 .map(|s| String::from_str(s).unwrap())
1154 .collect();
1155
1156 let expected_len = 2 * size_of::<SizeT>() + slices
1158 .iter()
1159 .map(|inner| inner.len() + size_of::<u8>()) .sum::<usize>();
1161 trace!("{}", Vec<&str>: slices, .sink=capture1);
1162 assert_eq!(capture1.len(), expected_len);
1163 trace!("{}", Vec<String>: owning, .sink=capture2);
1164 assert_eq!(capture2.len(), expected_len);
1165
1166 assert_eq!(
1167 capture1[size_of::<SizeT>()..],
1168 capture2[size_of::<SizeT>()..]
1169 );
1170 }
1171}