error2/backtrace/
mod.rs

1mod double_locations;
2mod message;
3
4use std::{any, error::Error, fmt, mem};
5
6use self::{double_locations::DoubleLocations, message::Message};
7use crate::Location;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub(crate) enum BakctraceEntry {
12    Message(Message),
13    Locations(DoubleLocations),
14}
15
16const _: () = {
17    ["Size of `Message`"][mem::size_of::<Message>() - 24usize];
18    ["Size of `DoubleLocations`"][mem::size_of::<DoubleLocations>() - 24usize];
19    ["`Message` and `DoubleLocations` must have the same size"]
20        [mem::size_of::<Message>() - mem::size_of::<DoubleLocations>()];
21    ["Size of `BakctraceEntry`"][mem::size_of::<BakctraceEntry>() - 32usize];
22};
23
24#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct Backtrace {
27    entries: Vec<BakctraceEntry>,
28}
29
30impl fmt::Debug for Backtrace {
31    #[inline]
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "Backtrace {{ ... }}")
34    }
35}
36
37impl Backtrace {
38    #[doc(hidden)]
39    #[inline]
40    pub const fn new() -> Self {
41        Self {
42            entries: Vec::new(),
43        }
44    }
45
46    #[doc(hidden)]
47    pub fn with_head<E: Error>(source: &E) -> Backtrace {
48        fn inner(type_name: &'static str, display: String) -> Backtrace {
49            Backtrace {
50                entries: vec![BakctraceEntry::Message(Message::new(type_name, display))],
51            }
52        }
53
54        let type_name = any::type_name::<E>();
55        let display = source.to_string();
56
57        inner(type_name, display)
58    }
59
60    pub(crate) fn push_error(
61        &mut self,
62        type_name: &'static str,
63        display: String,
64        location: Location,
65    ) {
66        self.entries
67            .push(BakctraceEntry::Message(Message::new(type_name, display)));
68
69        self.entries
70            .push(BakctraceEntry::Locations(DoubleLocations::new(location)));
71    }
72
73    pub(crate) const fn head_and_entries(&self) -> (Option<&Message>, &[BakctraceEntry]) {
74        let entries = self.entries.as_slice();
75
76        match entries {
77            [] => (None, &[]),
78            [BakctraceEntry::Locations(_), ..] => unreachable!(),
79            [BakctraceEntry::Message(first), rest @ ..] => match rest {
80                [] => (Some(first), &[]),
81                [BakctraceEntry::Message(_second), ..] => (Some(first), rest),
82                [BakctraceEntry::Locations(_second), ..] => (None, entries),
83            },
84        }
85    }
86
87    pub(crate) fn push_location(&mut self, location: Location) {
88        debug_assert!(matches!(
89            self.entries.first(),
90            Some(BakctraceEntry::Message(_))
91        ));
92
93        let entry = self
94            .entries
95            .last_mut()
96            .expect("there is must at least one message entry");
97
98        match entry {
99            BakctraceEntry::Locations(locations) if !locations.is_full() => {
100                let l = locations.push(location);
101                debug_assert!(l.is_none());
102            }
103            BakctraceEntry::Message(_) | BakctraceEntry::Locations(_) => {
104                self.entries
105                    .push(BakctraceEntry::Locations(DoubleLocations::new(location)));
106            }
107        }
108    }
109
110    pub fn error_message(&self) -> Box<str> {
111        crate::extract_error_message(self)
112    }
113}