musli_common/context/
rich_error.rs1use core::fmt;
2use core::mem::take;
3use core::ops::Range;
4
5pub struct RichError<'a, S, E> {
7 path: &'a [Step<S>],
8 path_cap: usize,
9 range: Range<usize>,
10 error: &'a E,
11}
12
13impl<'a, S, E> RichError<'a, S, E> {
14 pub(crate) fn new(
15 path: &'a [Step<S>],
16 path_cap: usize,
17 range: Range<usize>,
18 error: &'a E,
19 ) -> Self {
20 Self {
21 path,
22 path_cap,
23 range,
24 error,
25 }
26 }
27}
28
29impl<'a, S, E> fmt::Display for RichError<'a, S, E>
30where
31 S: fmt::Display,
32 E: fmt::Display,
33{
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 let path = format_path(self.path, self.path_cap);
36
37 if self.range.start != 0 || self.range.end != 0 {
38 if self.range.start == self.range.end {
39 write!(f, "{path}: {} (at byte {})", self.error, self.range.start)?;
40 } else {
41 write!(
42 f,
43 "{path}: {} (at bytes {}-{})",
44 self.error, self.range.start, self.range.end
45 )?;
46 }
47 } else {
48 write!(f, "{path}: {}", self.error)?;
49 }
50
51 Ok(())
52 }
53}
54
55#[derive(Debug, Clone)]
57pub(crate) enum Step<S> {
58 Struct(&'static str),
59 Enum(&'static str),
60 Variant(&'static str),
61 Named(&'static str),
62 Unnamed(u32),
63 Index(usize),
64 Key(S),
65}
66
67fn format_path<S>(path: &[Step<S>], path_cap: usize) -> impl fmt::Display + '_
68where
69 S: fmt::Display,
70{
71 FormatPath { path, path_cap }
72}
73
74struct FormatPath<'a, S> {
75 path: &'a [Step<S>],
76 path_cap: usize,
77}
78
79impl<'a, S> fmt::Display for FormatPath<'a, S>
80where
81 S: fmt::Display,
82{
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 let mut has_type = false;
85 let mut has_field = false;
86 let mut level = 0;
87
88 for step in self.path {
89 match step {
90 Step::Struct(name) => {
91 if take(&mut has_field) {
92 write!(f, " = ")?;
93 }
94
95 write!(f, "{name}")?;
96 has_type = true;
97 }
98 Step::Enum(name) => {
99 if take(&mut has_field) {
100 write!(f, " = ")?;
101 }
102
103 write!(f, "{name}::")?;
104 }
105 Step::Variant(name) => {
106 if take(&mut has_field) {
107 write!(f, " = ")?;
108 }
109
110 write!(f, "{name}")?;
111 has_type = true;
112 }
113 Step::Named(name) => {
114 if take(&mut has_type) {
115 write!(f, " {{ ")?;
116 level += 1;
117 }
118
119 write!(f, ".{name}")?;
120 has_field = true;
121 }
122 Step::Unnamed(index) => {
123 if take(&mut has_type) {
124 write!(f, " {{ ")?;
125 level += 1;
126 }
127
128 write!(f, ".{index}")?;
129 has_field = true;
130 }
131 Step::Index(index) => {
132 if take(&mut has_type) {
133 write!(f, " {{ ")?;
134 level += 1;
135 }
136
137 write!(f, "[{index}]")?;
138 has_field = true;
139 }
140 Step::Key(key) => {
141 if take(&mut has_type) {
142 write!(f, " {{ ")?;
143 level += 1;
144 }
145
146 write!(f, "[{}]", key)?;
147 has_field = true;
148 }
149 }
150 }
151
152 for _ in 0..level {
153 write!(f, " }}")?;
154 }
155
156 match self.path_cap {
157 0 => {}
158 1 => write!(f, " .. *one capped step*")?,
159 n => write!(f, " .. *{n} capped steps*")?,
160 }
161
162 Ok(())
163 }
164}