error2/
backtrace.rs

1use std::{fmt, mem};
2
3use crate::{Location, StaticStr};
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub(crate) struct Message {
8    type_name: StaticStr,
9    display: Box<str>,
10    index: usize,
11}
12
13impl Message {
14    pub(crate) const fn type_name(&self) -> &StaticStr {
15        &self.type_name
16    }
17
18    pub(crate) const fn display(&self) -> &str {
19        &self.display
20    }
21
22    pub(crate) const fn index(&self) -> usize {
23        self.index
24    }
25
26    pub(crate) const fn is_head(&self) -> bool {
27        self.index == usize::MAX
28    }
29}
30
31#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct Backtrace {
34    messages: Vec<Message>,
35    locations: Vec<Location>,
36}
37
38impl fmt::Debug for Backtrace {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "Backtrace {{ ... }}")
41    }
42}
43
44impl Backtrace {
45    #[doc(hidden)]
46    pub fn new() -> Self {
47        Self {
48            messages: Vec::new(),
49            locations: Vec::new(),
50        }
51    }
52
53    #[doc(hidden)]
54    pub fn with_head(type_name: &'static str, display: String) -> Self {
55        Self {
56            messages: vec![Message {
57                type_name: type_name.into(),
58                display: display.into(),
59                index: usize::MAX,
60            }],
61            locations: Vec::new(),
62        }
63    }
64
65    #[doc(hidden)]
66    pub fn push_error(&mut self, type_name: &'static str, display: String, location: Location) {
67        let index = self.locations.len();
68
69        self.messages.push(Message {
70            type_name: type_name.into(),
71            display: display.into(),
72            index,
73        });
74
75        self.attach_location(location);
76    }
77
78    pub(crate) const fn head_and_messages(&self) -> (Option<&Message>, &[Message]) {
79        let messages = self.messages.as_slice();
80
81        match messages {
82            [] => (None, &[]),
83            [first, rest @ ..] if first.is_head() => (Some(first), rest),
84            _ => (None, messages),
85        }
86    }
87
88    pub(crate) const fn locations(&self) -> &Vec<Location> {
89        &self.locations
90    }
91
92    const fn has_head(&self) -> bool {
93        matches!(self.messages.as_slice().first(), Some(msg) if msg.is_head())
94    }
95
96    #[inline]
97    pub(crate) fn attach_location(&mut self, location: Location) {
98        debug_assert!(
99            if self.has_head() {
100                self.messages.len() > 1
101            } else {
102                !self.messages.is_empty()
103            }
104        );
105
106        self.locations.push(location);
107    }
108
109    pub(crate) fn take(&mut self) -> Backtrace {
110        Backtrace {
111            messages: mem::take(&mut self.messages),
112            locations: mem::take(&mut self.locations),
113        }
114    }
115}