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}