Skip to main content

emtrace/
lib.rs

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
171/// Trait for emtrace sinks.
172pub trait Sink {
173    /// The error that can happen when calling `out`.
174    /// Set this to `Infallible` if your implementation can't produce an error.
175    type OutError;
176    /// The error that can happen when calling `begin`.
177    /// Set this to `Infallible` if your implementation can't produce an error.
178    type BeginError;
179    /// The bytes passed to this function are the contents of the emitted trace
180    fn out(&mut self, b: &[u8]) -> Result<(), Self::OutError>;
181    /// Begin emitting a trace.
182    ///
183    /// This function is called by the `trace` macro just before starting to emit a trace.
184    /// It will provide the address of the format info bytes as `info_addr`,
185    /// and the total number of bytes that the trace will contain as `total_size`.
186    ///
187    /// If the trace contains dynamically sized data, then `total_size` is provided as
188    /// the minimal number of bytes that will be sent, bitwise ored with either `emtrace::NULL_TERMINATED` or
189    /// `emtrace::LENGTH_PREFIXED`, depending on the kind of dynamic data.
190    fn begin(&mut self, info_addr: PointerT, total_size: SizeT) -> Result<(), Self::BeginError>;
191}
192
193/// Initialize the trace, by serializing the virtual memory address of the
194/// magic constant into the given sink.
195pub 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    /// How many SizeT fields the type requires in the offset table
244    const NUM_OFFSET_TABLE_ENTRIES: usize = {
245        let mut n = 0;
246        // to store own size, and number of children
247        n += 2;
248        // to store offset to own id
249        n += 1;
250
251        let mut i = 0;
252        let mut remaining = Self::NUM_CHILDREN;
253
254        // iterate over all descendants
255        while remaining > 0 {
256            let descendant = Self::DESCENDANTS[i];
257
258            // to store descendant's size and number of children
259            n += 2;
260            // to store offsets to descendant's name, and id
261            n += 2;
262
263            remaining += descendant.3;
264            remaining -= 1;
265            i += 1;
266        }
267
268        n
269    };
270
271    /// how many bytes this type needs to describe its type to the parser
272    const INFO_SIZE: usize = {
273        let mut size = 0;
274        // to store own id as null-terminated string
275        size += Self::ID.len() + size_of::<u8>();
276
277        let mut i = 0;
278        let mut remaining = Self::NUM_CHILDREN;
279
280        // iterate over all descendants
281        while remaining > 0 {
282            let descendant = Self::DESCENDANTS[i];
283
284            // to store descendant's name as null-terminated string
285            size += descendant.0.len() + size_of::<u8>();
286            // to store descendant's id as null-terminated string
287            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/// The core macro for emitting a trace.
514///
515/// `trace_impl!` is the main macro that `trace!` and `traceln!` are built on.
516///
517/// The format string is the concatenation of all string literals before the first comma.
518/// After that come the values to be emitted, along with their types, e.g.:
519///
520/// ```rust
521/// # use emtrace::{trace_impl, Sink, traceln};
522/// # fn main() {
523/// trace_impl!("{} + {}" " = {}", i32: 1, i32: 2, i32: 3);
524/// # }
525/// ```
526///
527/// A type can be made traceable by implementing the `Trace` trait for it.
528///
529/// ### Customization
530///
531/// `trace_impl!` supports several customization options, passed after the trace arguments:
532///
533/// - **`.sink = <variable>`**: Specifies a sink to write the trace output to. The macro will
534///   mutably borrow the value for the duration of the call. It must implement the
535///   [`Sink`] trait. For example one could capture trace output in a buffer like so:
536///   ```rust
537///   # use emtrace::{trace_impl, Sink};
538///   # fn main() {
539///   let mut buf = Vec::new();
540///   trace_impl!("Hello", .sink = buf);
541///   // `buf` is still owned and contains the trace output
542///   assert!(!buf.is_empty());
543///   # }
544///   ```
545///
546/// - **`.sink_guard = <expr>`**: Specifies a sink that will be consumed by the macro. Like with
547///   `.sink=` the expression has to  evaluate to a value that implements [`Sink`].
548///   This value is moved into the macro and dropped at the end of the scope.
549///   This is ideal for sinks that manage a resource, like a `MutexGuard`,
550///   as it ensures the resource is released correctly.
551///   ```rust
552///   # use emtrace::{trace_impl, Sink};
553///   # use std::sync::Mutex;
554///   # fn main() {
555///   let sink = Mutex::new(Vec::new());
556///   trace_impl!("Hello", .sink_guard = sink.lock().unwrap());
557///   // The mutex is unlocked here as the guard has been dropped.
558///   # }
559///   ```
560///   By default, if neither `.sink` nor `.sink_guard` is provided, the trace is written to
561///   `std::io::stdout().lock()`.
562///
563/// - **`.section = "<section_name>"`**: Specifies the ELF section where the format string and
564///   metadata are stored. Defaults to `.emtrace`.
565///
566/// - **`.formatter = <expr>`**: Specifies how the format string should be interpreted by the consumer
567///   of the trace data. It can be one of `PY_FORMAT`, `C_STYLE_FORMAT`, or `NO_FORMAT`.
568///
569/// - **`.error_handler = <closure>`**: Provides a closure to handle potential errors during tracing.
570///   The closure receives a `Result<(), Error<BeginError, OutError>>`. If not provided, the `Result`
571///   is returned from the macro expansion.
572///   ```rust
573///   # use emtrace::{trace_impl, Sink, Error};
574///   # fn main() {
575///   trace_impl!("Hello", .error_handler = |res: Result<(), Error<_, _>>| {
576///       if res.is_err() {
577///           // Handle error
578///       }
579///   });
580///   # }
581///   ```
582///
583/// The macro returns the output of the provided error handler.
584///
585/// [`Sink`]: trait.Sink.html
586#[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                        // if there is at least one `,type: arg` pair in the macro arguments,
749                        // then this will overwrite the default NO_FORMAT formatter to PY_FORMAT
750                        $($(
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/// Emit a trace.
862///
863/// The first argument is a format string, the rest are pairs of the form `type:expression`.
864/// A trace is emitted - by default over stdout - containing the address of the format string, and
865/// the data inside the other parameters.
866///
867/// ```rust
868/// # use emtrace::trace;
869/// # fn main() {
870/// trace!("Hello, {}", str: "world");
871/// # }
872/// ```
873///
874/// ### Error Handling
875///
876/// By default, this macro will panic if an error occurs during tracing. To handle errors manually,
877/// use the `.handle_errors` option. This will cause the macro to return a `Result` instead of
878/// panicking, which you can then handle as needed.
879///
880/// ```rust
881/// # use emtrace::trace;
882/// # fn main() {
883/// let result = trace!("Hello", .handle_errors);
884/// if result.is_err() {
885///     // Handle the error
886/// }
887/// # }
888/// ```
889///
890/// For other customization options, see [`trace_impl!`] (this supports all the same options,
891/// except for `.error_handler=`).
892///
893/// [`trace_impl!`]: macro.trace_impl.html
894#[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/// Emit a trace with a trailing new line in the format string.
907///
908/// This macro is identical to [`trace!`], but it automatically appends a newline character (`\n`)
909/// to the format string.
910///
911/// ```rust
912/// # use emtrace::traceln;
913/// # fn main() {
914/// traceln!("This will be followed by a newline.");
915/// # }
916/// ```
917///
918/// ### Error Handling
919///
920/// Like `trace!`, this macro will panic on error by default. Use the `.handle_errors` option to
921/// receive a `Result` and handle errors manually.
922///
923/// ```rust
924/// # use emtrace::traceln;
925/// # fn main() {
926/// let result = traceln!("Hello", .handle_errors);
927/// if result.is_err() {
928///     // Handle the error
929/// }
930/// # }
931/// ```
932///
933/// For other customization options, see [`trace_impl!`] (this supports all the same options,
934/// except for `.error_handler=`).
935///
936/// [`trace!`]: macro.trace.html
937/// [`trace_impl!`]: macro.trace_impl.html
938#[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>() // for pointer, and length-prefix
1157            + slices
1158                .iter()
1159                .map(|inner| inner.len() + size_of::<u8>()) // for content and null-terminator
1160                .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}