musli/context/
trace.rs

1#![allow(clippy::type_complexity)]
2
3use core::cell::{Cell, UnsafeCell};
4use core::fmt;
5use core::mem::take;
6use core::ops::Range;
7use core::slice;
8
9use crate::alloc::{Allocator, String, Vec};
10
11use super::{Access, Shared};
12
13mod sealed {
14    use crate::alloc::Allocator;
15
16    pub trait Sealed {}
17    impl<A> Sealed for super::WithTraceImpl<A> where A: Allocator {}
18    impl Sealed for super::NoTraceImpl {}
19    impl Sealed for super::Trace {}
20    impl Sealed for super::NoTrace {}
21}
22
23/// Trait for marker types indicating the tracing mode to use.
24pub trait TraceMode: self::sealed::Sealed {
25    #[doc(hidden)]
26    type Impl<A>: TraceImpl<A>
27    where
28        A: Allocator;
29
30    #[doc(hidden)]
31    fn new_in<A>(alloc: A) -> Self::Impl<A>
32    where
33        A: Allocator;
34}
35
36/// The trait governing how tracing works in a [`DefaultContext`].
37///
38/// [`DefaultContext`]: super::DefaultContext
39pub trait TraceImpl<A>: self::sealed::Sealed {
40    #[doc(hidden)]
41    type Mark;
42
43    #[doc(hidden)]
44    fn clear(&self);
45
46    #[doc(hidden)]
47    fn advance(&self, n: usize);
48
49    #[doc(hidden)]
50    fn mark(&self) -> Self::Mark;
51
52    #[doc(hidden)]
53    fn restore(&self, mark: &Self::Mark);
54
55    #[doc(hidden)]
56    fn custom<T>(&self, alloc: A, message: &T)
57    where
58        T: 'static + Send + Sync + fmt::Display + fmt::Debug;
59
60    #[doc(hidden)]
61    fn message<T>(&self, alloc: A, message: &T)
62    where
63        T: fmt::Display;
64
65    #[doc(hidden)]
66    fn message_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
67    where
68        T: fmt::Display;
69
70    #[doc(hidden)]
71    fn custom_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
72    where
73        T: 'static + Send + Sync + fmt::Display + fmt::Debug;
74
75    #[doc(hidden)]
76    fn enter_named_field<T>(&self, name: &'static str, field: &T)
77    where
78        T: fmt::Display;
79
80    #[doc(hidden)]
81    fn enter_unnamed_field<T>(&self, index: u32, name: &T)
82    where
83        T: fmt::Display;
84
85    #[doc(hidden)]
86    fn leave_field(&self);
87
88    #[doc(hidden)]
89    fn enter_struct(&self, name: &'static str);
90
91    #[doc(hidden)]
92    fn leave_struct(&self);
93
94    #[doc(hidden)]
95    fn enter_enum(&self, name: &'static str);
96
97    #[doc(hidden)]
98    fn leave_enum(&self);
99
100    #[doc(hidden)]
101    fn enter_variant<T>(&self, name: &'static str, _: &T)
102    where
103        T: fmt::Display;
104
105    #[doc(hidden)]
106    fn leave_variant(&self);
107
108    #[doc(hidden)]
109    fn enter_sequence_index(&self, index: usize);
110
111    #[doc(hidden)]
112    fn leave_sequence_index(&self);
113
114    #[doc(hidden)]
115    fn enter_map_key<T>(&self, alloc: A, field: &T)
116    where
117        T: fmt::Display;
118
119    #[doc(hidden)]
120    fn leave_map_key(&self);
121}
122
123/// Marker type indicating that tracing is enabled.
124///
125/// See [`DefaultContext::with_trace`] for more information.
126///
127/// [`DefaultContext::with_trace`]: super::DefaultContext::with_trace
128#[non_exhaustive]
129pub struct Trace;
130
131impl TraceMode for Trace {
132    type Impl<A>
133        = WithTraceImpl<A>
134    where
135        A: Allocator;
136
137    #[inline]
138    fn new_in<A>(alloc: A) -> Self::Impl<A>
139    where
140        A: Allocator,
141    {
142        WithTraceImpl::new_in(alloc)
143    }
144}
145
146/// Trace configuration indicating that tracing is enabled through the allocator
147/// `A`.
148pub struct WithTraceImpl<A>
149where
150    A: Allocator,
151{
152    mark: Cell<usize>,
153    errors: UnsafeCell<Vec<(Range<usize>, String<A>), A>>,
154    path: UnsafeCell<Vec<Step<A>, A>>,
155    // How many elements of `path` we've gone over capacity.
156    cap: Cell<usize>,
157    include_type: bool,
158    access: Access,
159}
160
161impl<A> WithTraceImpl<A>
162where
163    A: Allocator,
164{
165    /// Construct a new tracing context inside of the given allocator.
166    #[inline]
167    pub(super) fn new_in(alloc: A) -> Self {
168        let errors = Vec::new_in(alloc);
169        let path = Vec::new_in(alloc);
170
171        Self {
172            mark: Cell::new(0),
173            errors: UnsafeCell::new(errors),
174            path: UnsafeCell::new(path),
175            cap: Cell::new(0),
176            include_type: false,
177            access: Access::new(),
178        }
179    }
180
181    #[inline]
182    pub(super) fn include_type(&mut self) {
183        self.include_type = true;
184    }
185
186    /// Generate a line-separated report of all collected errors.
187    #[inline]
188    pub fn report(&self) -> Report<'_, A> {
189        Report {
190            errors: self.errors(),
191        }
192    }
193
194    #[inline]
195    pub(super) fn errors(&self) -> Errors<'_, A> {
196        let access = self.access.shared();
197
198        Errors {
199            path: unsafe { (*self.path.get()).as_slice() },
200            errors: unsafe { (*self.errors.get()).as_slice().iter() },
201            cap: self.cap.get(),
202            _access: access,
203        }
204    }
205
206    /// Push a path.
207    #[inline]
208    fn push_path(&self, step: Step<A>) {
209        let _access = self.access.exclusive();
210
211        // SAFETY: We've checked that we have exclusive access just above.
212        let path = unsafe { &mut (*self.path.get()) };
213
214        if path.push(step).is_err() {
215            self.cap.set(&self.cap.get() + 1);
216        }
217    }
218
219    /// Pop the last path.
220    #[inline]
221    fn pop_path(&self) {
222        let cap = self.cap.get();
223
224        if cap > 0 {
225            self.cap.set(cap - 1);
226            return;
227        }
228
229        let _access = self.access.exclusive();
230
231        // SAFETY: We've checked that we have exclusive access just above.
232        unsafe {
233            (*self.path.get()).pop();
234        }
235    }
236
237    #[inline]
238    fn format_string<T>(&self, alloc: A, value: T) -> Option<String<A>>
239    where
240        T: fmt::Display,
241    {
242        use core::fmt::Write;
243
244        let mut string = String::new_in(alloc);
245        write!(string, "{value}").ok()?;
246        Some(string)
247    }
248
249    /// Push an error into the collection.
250    #[inline]
251    fn push_error(&self, range: Range<usize>, error: String<A>) {
252        let _access = self.access.exclusive();
253
254        // SAFETY: We've checked that we have exclusive access just above.
255        unsafe {
256            _ = (*self.errors.get()).push((range, error));
257        }
258    }
259}
260
261impl<A> TraceImpl<A> for WithTraceImpl<A>
262where
263    A: Allocator,
264{
265    type Mark = usize;
266
267    #[inline]
268    fn clear(&self) {
269        self.mark.set(0);
270        let _access = self.access.exclusive();
271
272        // SAFETY: We have acquired exclusive access just above.
273        unsafe {
274            (*self.errors.get()).clear();
275            (*self.path.get()).clear();
276        }
277    }
278
279    #[inline]
280    fn advance(&self, n: usize) {
281        self.mark.set(self.mark.get().wrapping_add(n));
282    }
283
284    #[inline]
285    fn mark(&self) -> Self::Mark {
286        self.mark.get()
287    }
288
289    #[inline]
290    fn restore(&self, mark: &Self::Mark) {
291        self.mark.set(*mark);
292    }
293
294    #[inline]
295    fn custom<T>(&self, alloc: A, message: &T)
296    where
297        T: 'static + Send + Sync + fmt::Display + fmt::Debug,
298    {
299        if let Some(string) = self.format_string(alloc, message) {
300            self.push_error(self.mark.get()..self.mark.get(), string);
301        }
302    }
303
304    #[inline]
305    fn message<T>(&self, alloc: A, message: &T)
306    where
307        T: fmt::Display,
308    {
309        if let Some(string) = self.format_string(alloc, message) {
310            self.push_error(self.mark.get()..self.mark.get(), string);
311        }
312    }
313
314    #[inline]
315    fn message_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
316    where
317        T: fmt::Display,
318    {
319        if let Some(string) = self.format_string(alloc, message) {
320            self.push_error(*mark..self.mark.get(), string);
321        }
322    }
323
324    #[inline]
325    fn custom_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
326    where
327        T: 'static + Send + Sync + fmt::Display + fmt::Debug,
328    {
329        if let Some(string) = self.format_string(alloc, message) {
330            self.push_error(*mark..self.mark.get(), string);
331        }
332    }
333
334    #[inline]
335    fn enter_named_field<T>(&self, name: &'static str, _: &T)
336    where
337        T: fmt::Display,
338    {
339        self.push_path(Step::Named(name));
340    }
341
342    #[inline]
343    fn enter_unnamed_field<T>(&self, index: u32, _: &T)
344    where
345        T: fmt::Display,
346    {
347        self.push_path(Step::Unnamed(index));
348    }
349
350    #[inline]
351    fn leave_field(&self) {
352        self.pop_path();
353    }
354
355    #[inline]
356    fn enter_struct(&self, name: &'static str) {
357        if self.include_type {
358            self.push_path(Step::Struct(name));
359        }
360    }
361
362    #[inline]
363    fn leave_struct(&self) {
364        if self.include_type {
365            self.pop_path();
366        }
367    }
368
369    #[inline]
370    fn enter_enum(&self, name: &'static str) {
371        if self.include_type {
372            self.push_path(Step::Enum(name));
373        }
374    }
375
376    #[inline]
377    fn leave_enum(&self) {
378        if self.include_type {
379            self.pop_path();
380        }
381    }
382
383    #[inline]
384    fn enter_variant<T>(&self, name: &'static str, _: &T) {
385        self.push_path(Step::Variant(name));
386    }
387
388    #[inline]
389    fn leave_variant(&self) {
390        self.pop_path();
391    }
392
393    #[inline]
394    fn enter_sequence_index(&self, index: usize) {
395        self.push_path(Step::Index(index));
396    }
397
398    #[inline]
399    fn leave_sequence_index(&self) {
400        self.pop_path();
401    }
402
403    #[inline]
404    fn enter_map_key<T>(&self, alloc: A, field: &T)
405    where
406        T: fmt::Display,
407    {
408        if let Some(string) = self.format_string(alloc, field) {
409            self.push_path(Step::Key(string));
410        }
411    }
412
413    #[inline]
414    fn leave_map_key(&self) {
415        self.pop_path();
416    }
417}
418
419#[non_exhaustive]
420pub struct NoTraceImpl;
421
422/// Trace configuration indicating that tracing is fully disabled.
423///
424/// This is the default behavior you get when calling [`new`] or [`new_in`].
425///
426/// [`new`]: super::new
427/// [`new_in`]: super::new_in
428#[non_exhaustive]
429pub struct NoTrace;
430
431impl TraceMode for NoTrace {
432    type Impl<A>
433        = NoTraceImpl
434    where
435        A: Allocator;
436
437    #[inline]
438    fn new_in<A>(_: A) -> Self::Impl<A>
439    where
440        A: Allocator,
441    {
442        NoTraceImpl
443    }
444}
445
446impl<A> TraceImpl<A> for NoTraceImpl
447where
448    A: Allocator,
449{
450    type Mark = ();
451
452    #[inline]
453    fn clear(&self) {}
454
455    #[inline]
456    fn mark(&self) -> Self::Mark {}
457
458    #[inline]
459    fn restore(&self, mark: &Self::Mark) -> Self::Mark {
460        _ = mark;
461    }
462
463    #[inline]
464    fn advance(&self, n: usize) {
465        _ = n;
466    }
467
468    #[inline]
469    fn custom<T>(&self, alloc: A, message: &T)
470    where
471        T: 'static + Send + Sync + fmt::Display + fmt::Debug,
472    {
473        _ = alloc;
474        _ = message;
475    }
476
477    #[inline]
478    fn message<T>(&self, alloc: A, message: &T)
479    where
480        T: fmt::Display,
481    {
482        _ = alloc;
483        _ = message;
484    }
485
486    #[inline]
487    fn message_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
488    where
489        T: fmt::Display,
490    {
491        _ = alloc;
492        _ = mark;
493        _ = message;
494    }
495
496    #[inline]
497    fn custom_at<T>(&self, alloc: A, mark: &Self::Mark, message: &T)
498    where
499        T: 'static + Send + Sync + fmt::Display + fmt::Debug,
500    {
501        _ = alloc;
502        _ = mark;
503        _ = message;
504    }
505
506    #[inline]
507    fn enter_named_field<T>(&self, name: &'static str, field: &T)
508    where
509        T: fmt::Display,
510    {
511        _ = name;
512        _ = field;
513    }
514
515    #[inline]
516    fn enter_unnamed_field<T>(&self, index: u32, field: &T)
517    where
518        T: fmt::Display,
519    {
520        _ = index;
521        _ = field;
522    }
523
524    #[inline]
525    fn leave_field(&self) {}
526
527    #[inline]
528    fn enter_struct(&self, name: &'static str) {
529        _ = name;
530    }
531
532    #[inline]
533    fn leave_struct(&self) {}
534
535    #[inline]
536    fn enter_enum(&self, name: &'static str) {
537        _ = name;
538    }
539
540    #[inline]
541    fn leave_enum(&self) {}
542
543    #[inline]
544    fn enter_variant<T>(&self, name: &'static str, variant: &T)
545    where
546        T: fmt::Display,
547    {
548        _ = name;
549        _ = variant;
550    }
551
552    #[inline]
553    fn leave_variant(&self) {}
554
555    #[inline]
556    fn enter_sequence_index(&self, index: usize) {
557        _ = index;
558    }
559
560    #[inline]
561    fn leave_sequence_index(&self) {}
562
563    #[inline]
564    fn enter_map_key<T>(&self, alloc: A, field: &T)
565    where
566        T: fmt::Display,
567    {
568        _ = alloc;
569        _ = field;
570    }
571
572    #[inline]
573    fn leave_map_key(&self) {}
574}
575
576/// A line-separated report of all errors.
577///
578/// See [`DefaultContext::report`].
579///
580/// [`DefaultContext::report`]: super::DefaultContext::report
581pub struct Report<'a, A>
582where
583    A: Allocator,
584{
585    errors: Errors<'a, A>,
586}
587
588impl<A> fmt::Display for Report<'_, A>
589where
590    A: Allocator,
591{
592    #[inline]
593    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594        for error in self.errors.clone() {
595            writeln!(f, "{error}")?;
596        }
597
598        Ok(())
599    }
600}
601
602/// An iterator over available errors.
603///
604/// See [`DefaultContext::errors`].
605///
606/// [`DefaultContext::errors`]: super::DefaultContext::errors
607pub struct Errors<'a, A>
608where
609    A: Allocator,
610{
611    path: &'a [Step<A>],
612    cap: usize,
613    errors: slice::Iter<'a, (Range<usize>, String<A>)>,
614    _access: Shared<'a>,
615}
616
617impl<'a, A> Iterator for Errors<'a, A>
618where
619    A: Allocator,
620{
621    type Item = Error<'a, A>;
622
623    #[inline]
624    fn next(&mut self) -> Option<Self::Item> {
625        let (range, error) = self.errors.next()?;
626        Some(Error::new(self.path, self.cap, range.clone(), error))
627    }
628}
629
630impl<A> Clone for Errors<'_, A>
631where
632    A: Allocator,
633{
634    #[inline]
635    fn clone(&self) -> Self {
636        Self {
637            path: self.path,
638            cap: self.cap,
639            errors: self.errors.clone(),
640            _access: self._access.clone(),
641        }
642    }
643}
644
645/// A collected error which has been context decorated.
646pub struct Error<'a, A>
647where
648    A: Allocator,
649{
650    path: &'a [Step<A>],
651    cap: usize,
652    range: Range<usize>,
653    error: &'a str,
654}
655
656impl<'a, A> Error<'a, A>
657where
658    A: Allocator,
659{
660    #[inline]
661    fn new(path: &'a [Step<A>], cap: usize, range: Range<usize>, error: &'a str) -> Self {
662        Self {
663            path,
664            cap,
665            range,
666            error,
667        }
668    }
669}
670
671impl<A> fmt::Display for Error<'_, A>
672where
673    A: Allocator,
674{
675    #[inline]
676    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
677        let path = FormatPath::new(self.path, self.cap);
678
679        if self.range.start != 0 || self.range.end != 0 {
680            if self.range.start == self.range.end {
681                write!(f, "{path}: {} (at byte {})", self.error, self.range.start)?;
682            } else {
683                write!(
684                    f,
685                    "{path}: {} (at bytes {}-{})",
686                    self.error, self.range.start, self.range.end
687                )?;
688            }
689        } else {
690            write!(f, "{path}: {}", self.error)?;
691        }
692
693        Ok(())
694    }
695}
696
697/// A single traced step.
698#[derive(Debug)]
699enum Step<A>
700where
701    A: Allocator,
702{
703    Struct(&'static str),
704    Enum(&'static str),
705    Variant(&'static str),
706    Named(&'static str),
707    Unnamed(u32),
708    Index(usize),
709    Key(String<A>),
710}
711
712struct FormatPath<'a, A>
713where
714    A: Allocator,
715{
716    path: &'a [Step<A>],
717    cap: usize,
718}
719
720impl<'a, A> FormatPath<'a, A>
721where
722    A: Allocator,
723{
724    #[inline]
725    fn new(path: &'a [Step<A>], cap: usize) -> Self {
726        Self { path, cap }
727    }
728}
729
730impl<A> fmt::Display for FormatPath<'_, A>
731where
732    A: Allocator,
733{
734    #[inline]
735    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736        let mut has_type = false;
737        let mut has_field = false;
738        let mut level = 0;
739
740        for step in self.path {
741            match step {
742                Step::Struct(name) => {
743                    if take(&mut has_field) {
744                        write!(f, " = ")?;
745                    }
746
747                    write!(f, "{name}")?;
748                    has_type = true;
749                }
750                Step::Enum(name) => {
751                    if take(&mut has_field) {
752                        write!(f, " = ")?;
753                    }
754
755                    write!(f, "{name}::")?;
756                }
757                Step::Variant(name) => {
758                    if take(&mut has_field) {
759                        write!(f, " = ")?;
760                    }
761
762                    write!(f, "{name}")?;
763                    has_type = true;
764                }
765                Step::Named(name) => {
766                    if take(&mut has_type) {
767                        write!(f, " {{ ")?;
768                        level += 1;
769                    }
770
771                    write!(f, ".{name}")?;
772                    has_field = true;
773                }
774                Step::Unnamed(index) => {
775                    if take(&mut has_type) {
776                        write!(f, " {{ ")?;
777                        level += 1;
778                    }
779
780                    write!(f, ".{index}")?;
781                    has_field = true;
782                }
783                Step::Index(index) => {
784                    if take(&mut has_type) {
785                        write!(f, " {{ ")?;
786                        level += 1;
787                    }
788
789                    write!(f, "[{index}]")?;
790                    has_field = true;
791                }
792                Step::Key(key) => {
793                    if take(&mut has_type) {
794                        write!(f, " {{ ")?;
795                        level += 1;
796                    }
797
798                    write!(f, "[{}]", key)?;
799                    has_field = true;
800                }
801            }
802        }
803
804        for _ in 0..level {
805            write!(f, " }}")?;
806        }
807
808        match self.cap {
809            0 => {}
810            1 => write!(f, " .. *one capped step*")?,
811            n => write!(f, " .. *{n} capped steps*")?,
812        }
813
814        Ok(())
815    }
816}