1#[cfg(feature = "rich-diagnostics")]
2use ariadne::{Color, Config, IndexType, Label, Report, ReportKind, Source};
3
4use alloc::string::String;
5
6use facet_core::{Def, Shape};
7use facet_reflect::ReflectError;
8use owo_colors::OwoColorize;
9
10use crate::{Outcome, Span};
11
12#[derive(Debug)]
14pub struct DeserError<'input> {
15 pub input: alloc::borrow::Cow<'input, [u8]>,
17
18 pub span: Span,
20
21 pub kind: DeserErrorKind,
23}
24
25impl DeserError<'_> {
26 pub fn into_owned(self) -> DeserError<'static> {
28 DeserError {
29 input: self.input.into_owned().into(),
30 span: self.span,
31 kind: self.kind,
32 }
33 }
34
35 pub fn with_span(mut self, span: Span) -> Self {
37 self.span = span;
38 self
39 }
40}
41
42#[derive(Debug, PartialEq, Clone)]
44pub enum DeserErrorKind {
45 UnexpectedByte {
47 got: u8,
49 wanted: &'static str,
51 },
52 UnexpectedChar {
54 got: char,
56 wanted: &'static str,
58 },
59 UnexpectedOutcome {
61 got: Outcome<'static>,
63 wanted: &'static str,
65 },
66 UnexpectedEof {
68 wanted: &'static str,
70 },
71 MissingField(&'static str),
73 NumberOutOfRange(f64),
75 StringAsNumber(String),
77 UnknownField {
79 field_name: String,
81 shape: &'static Shape,
83 },
84 InvalidUtf8(String),
86 ReflectError(ReflectError),
88 Unimplemented(&'static str),
90 UnsupportedType {
92 got: &'static Shape,
94
95 wanted: &'static str,
97 },
98 NoSuchVariant {
100 name: String,
102
103 enum_shape: &'static Shape,
105 },
106}
107
108impl<'input> DeserError<'input> {
109 pub fn new(kind: DeserErrorKind, input: &'input [u8], span: Span) -> Self {
111 Self {
112 input: alloc::borrow::Cow::Borrowed(input),
113 span,
114 kind,
115 }
116 }
117
118 pub(crate) fn new_reflect(e: ReflectError, input: &'input [u8], span: Span) -> Self {
120 DeserError::new(DeserErrorKind::ReflectError(e), input, span)
121 }
122
123 pub fn message(&self) -> DeserErrorMessage<'_> {
125 DeserErrorMessage(self)
126 }
127}
128
129pub struct DeserErrorMessage<'a>(&'a DeserError<'a>);
131
132impl core::fmt::Display for DeserErrorMessage<'_> {
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 match &self.0.kind {
135 DeserErrorKind::UnexpectedByte { got, wanted } => write!(
136 f,
137 "Unexpected byte: got 0x{:02X}, wanted {}",
138 got.red(),
139 wanted.yellow()
140 ),
141 DeserErrorKind::UnexpectedChar { got, wanted } => write!(
142 f,
143 "Unexpected character: got '{}', wanted {}",
144 got.red(),
145 wanted.yellow()
146 ),
147 DeserErrorKind::UnexpectedOutcome { got, wanted } => {
148 write!(f, "Unexpected {}, wanted {}", got.red(), wanted.yellow())
149 }
150 DeserErrorKind::UnexpectedEof { wanted } => {
151 write!(f, "Unexpected end of file: wanted {}", wanted.red())
152 }
153 DeserErrorKind::MissingField(fld) => write!(f, "Missing required field: {}", fld.red()),
154 DeserErrorKind::NumberOutOfRange(n) => {
155 write!(f, "Number out of range: {}", n.red())
156 }
157 DeserErrorKind::StringAsNumber(s) => {
158 write!(f, "Expected a string but got number: {}", s.red())
159 }
160 DeserErrorKind::UnknownField { field_name, shape } => {
161 write!(
162 f,
163 "Unknown field: {} for shape {}",
164 field_name.red(),
165 shape.yellow()
166 )
167 }
168 DeserErrorKind::InvalidUtf8(e) => write!(f, "Invalid UTF-8 encoding: {}", e.red()),
169 DeserErrorKind::ReflectError(e) => write!(f, "{e}"),
170 DeserErrorKind::Unimplemented(s) => {
171 write!(f, "Feature not yet implemented: {}", s.yellow())
172 }
173 DeserErrorKind::UnsupportedType { got, wanted } => {
174 write!(
175 f,
176 "Unsupported type: got {}, wanted {}",
177 got.red(),
178 wanted.green()
179 )
180 }
181 DeserErrorKind::NoSuchVariant { name, enum_shape } => match enum_shape.def {
182 Def::Enum(ed) => {
183 write!(
184 f,
185 "Enum variant not found: {} in enum {}. Available variants: [",
186 name.red(),
187 enum_shape.yellow()
188 )?;
189
190 let mut first = true;
191 for variant in ed.variants.iter() {
192 if !first {
193 write!(f, ", ")?;
194 }
195 write!(f, "{}", variant.name.green())?;
196 first = false;
197 }
198
199 write!(f, "]")
200 }
201 _ => {
202 write!(
203 f,
204 "Enum variant not found: {} in enum {}. No variants available (not an enum)",
205 name.red(),
206 enum_shape.yellow()
207 )
208 }
209 },
210 }
211 }
212}
213
214#[cfg(not(feature = "rich-diagnostics"))]
215impl core::fmt::Display for DeserError<'_> {
216 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
217 write!(f, "{} at byte {}", self.message(), self.span.start(),)
218 }
219}
220
221#[cfg(feature = "rich-diagnostics")]
222impl core::fmt::Display for DeserError<'_> {
223 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224 let Ok(input_str) = core::str::from_utf8(&self.input[..]) else {
225 return write!(f, "(JSON input was invalid UTF-8)");
226 };
227
228 let source_id = "json";
229 let span_start = self.span.start();
230 let span_end = self.span.end();
231
232 let mut report = Report::build(ReportKind::Error, (source_id, span_start..span_end))
233 .with_config(Config::new().with_index_type(IndexType::Byte));
234
235 let label = Label::new((source_id, span_start..span_end))
236 .with_message(self.message())
237 .with_color(Color::Red);
238
239 report = report.with_label(label);
240
241 let source = Source::from(input_str);
242
243 struct FmtWriter<'a, 'b: 'a> {
244 f: &'a mut core::fmt::Formatter<'b>,
245 error: Option<core::fmt::Error>,
246 }
247
248 impl core::fmt::Write for FmtWriter<'_, '_> {
249 fn write_str(&mut self, s: &str) -> core::fmt::Result {
250 if self.error.is_some() {
251 return Err(core::fmt::Error);
253 }
254 if let Err(e) = self.f.write_str(s) {
255 self.error = Some(e);
256 Err(core::fmt::Error)
257 } else {
258 Ok(())
259 }
260 }
261 }
262
263 struct IoWriter<'a, 'b: 'a> {
264 inner: FmtWriter<'a, 'b>,
265 }
266
267 impl std::io::Write for IoWriter<'_, '_> {
268 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
269 match core::str::from_utf8(buf) {
270 Ok(s) => match core::fmt::Write::write_str(&mut self.inner, s) {
271 Ok(()) => Ok(buf.len()),
272 Err(_) => Err(std::io::ErrorKind::Other.into()),
273 },
274 Err(_) => Err(std::io::ErrorKind::InvalidData.into()),
275 }
276 }
277 fn flush(&mut self) -> std::io::Result<()> {
278 Ok(())
279 }
280 }
281
282 let cache = (source_id, &source);
283
284 let fmt_writer = FmtWriter { f, error: None };
285 let mut io_writer = IoWriter { inner: fmt_writer };
286
287 if report.finish().write(cache, &mut io_writer).is_err() {
288 return write!(f, "Error formatting with ariadne");
289 }
290
291 if io_writer.inner.error.is_some() {
293 return write!(f, "Error writing ariadne output to fmt::Formatter");
294 }
295
296 Ok(())
297 }
298}
299
300impl core::error::Error for DeserError<'_> {}