1#[cfg(feature = "rich-diagnostics")]
2use ariadne::{Color, Config, IndexType, Label, Report, ReportKind, Source};
3
4use alloc::string::String;
5
6use facet_core::{Shape, Type, UserType};
7use facet_reflect::{ReflectError, VariantError};
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 VariantError(VariantError),
108}
109
110impl<'input> DeserError<'input> {
111 pub fn new(kind: DeserErrorKind, input: &'input [u8], span: Span) -> Self {
113 Self {
114 input: alloc::borrow::Cow::Borrowed(input),
115 span,
116 kind,
117 }
118 }
119
120 pub(crate) fn new_reflect(e: ReflectError, input: &'input [u8], span: Span) -> Self {
122 DeserError::new(DeserErrorKind::ReflectError(e), input, span)
123 }
124
125 pub fn message(&self) -> DeserErrorMessage<'_> {
127 DeserErrorMessage(self)
128 }
129}
130
131pub struct DeserErrorMessage<'a>(&'a DeserError<'a>);
133
134impl core::fmt::Display for DeserErrorMessage<'_> {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 match &self.0.kind {
137 DeserErrorKind::UnexpectedByte { got, wanted } => write!(
138 f,
139 "Unexpected byte: got 0x{:02X}, wanted {}",
140 got.red(),
141 wanted.yellow()
142 ),
143 DeserErrorKind::UnexpectedChar { got, wanted } => write!(
144 f,
145 "Unexpected character: got '{}', wanted {}",
146 got.red(),
147 wanted.yellow()
148 ),
149 DeserErrorKind::UnexpectedOutcome { got, wanted } => {
150 write!(f, "Unexpected {}, wanted {}", got.red(), wanted.yellow())
151 }
152 DeserErrorKind::UnexpectedEof { wanted } => {
153 write!(f, "Unexpected end of file: wanted {}", wanted.red())
154 }
155 DeserErrorKind::MissingField(fld) => write!(f, "Missing required field: {}", fld.red()),
156 DeserErrorKind::NumberOutOfRange(n) => {
157 write!(f, "Number out of range: {}", n.red())
158 }
159 DeserErrorKind::StringAsNumber(s) => {
160 write!(f, "Expected a string but got number: {}", s.red())
161 }
162 DeserErrorKind::UnknownField { field_name, shape } => {
163 write!(
164 f,
165 "Unknown field: {} for shape {}",
166 field_name.red(),
167 shape.yellow()
168 )
169 }
170 DeserErrorKind::InvalidUtf8(e) => write!(f, "Invalid UTF-8 encoding: {}", e.red()),
171 DeserErrorKind::ReflectError(e) => write!(f, "{e}"),
172 DeserErrorKind::Unimplemented(s) => {
173 write!(f, "Feature not yet implemented: {}", s.yellow())
174 }
175 DeserErrorKind::UnsupportedType { got, wanted } => {
176 write!(
177 f,
178 "Unsupported type: got {}, wanted {}",
179 got.red(),
180 wanted.green()
181 )
182 }
183 DeserErrorKind::NoSuchVariant { name, enum_shape } => {
184 if let Type::User(UserType::Enum(ed)) = enum_shape.ty {
185 write!(
186 f,
187 "Enum variant not found: {} in enum {}. Available variants: [",
188 name.red(),
189 enum_shape.yellow()
190 )?;
191
192 let mut first = true;
193 for variant in ed.variants.iter() {
194 if !first {
195 write!(f, ", ")?;
196 }
197 write!(f, "{}", variant.name.green())?;
198 first = false;
199 }
200
201 write!(f, "]")?;
202 Ok(())
203 } else {
204 write!(
205 f,
206 "Enum variant not found: {} in non-enum type {}",
207 name.red(),
208 enum_shape.yellow()
209 )?;
210 Ok(())
211 }
212 }
213 DeserErrorKind::VariantError(e) => {
214 write!(f, "Variant error: {e}")
215 }
216 }
217 }
218}
219
220#[cfg(not(feature = "rich-diagnostics"))]
221impl core::fmt::Display for DeserError<'_> {
222 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
223 write!(f, "{} at byte {}", self.message(), self.span.start(),)
224 }
225}
226
227#[cfg(feature = "rich-diagnostics")]
228impl core::fmt::Display for DeserError<'_> {
229 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230 let Ok(input_str) = core::str::from_utf8(&self.input[..]) else {
231 return write!(f, "(JSON input was invalid UTF-8)");
232 };
233
234 let source_id = "json";
235 let span_start = self.span.start();
236 let span_end = self.span.end();
237
238 let mut report = Report::build(ReportKind::Error, (source_id, span_start..span_end))
239 .with_config(Config::new().with_index_type(IndexType::Byte));
240
241 let label = Label::new((source_id, span_start..span_end))
242 .with_message(self.message())
243 .with_color(Color::Red);
244
245 report = report.with_label(label);
246
247 let source = Source::from(input_str);
248
249 struct FmtWriter<'a, 'b: 'a> {
250 f: &'a mut core::fmt::Formatter<'b>,
251 error: Option<core::fmt::Error>,
252 }
253
254 impl core::fmt::Write for FmtWriter<'_, '_> {
255 fn write_str(&mut self, s: &str) -> core::fmt::Result {
256 if self.error.is_some() {
257 return Err(core::fmt::Error);
259 }
260 if let Err(e) = self.f.write_str(s) {
261 self.error = Some(e);
262 Err(core::fmt::Error)
263 } else {
264 Ok(())
265 }
266 }
267 }
268
269 struct IoWriter<'a, 'b: 'a> {
270 inner: FmtWriter<'a, 'b>,
271 }
272
273 impl std::io::Write for IoWriter<'_, '_> {
274 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
275 match core::str::from_utf8(buf) {
276 Ok(s) => match core::fmt::Write::write_str(&mut self.inner, s) {
277 Ok(()) => Ok(buf.len()),
278 Err(_) => Err(std::io::ErrorKind::Other.into()),
279 },
280 Err(_) => Err(std::io::ErrorKind::InvalidData.into()),
281 }
282 }
283 fn flush(&mut self) -> std::io::Result<()> {
284 Ok(())
285 }
286 }
287
288 let cache = (source_id, &source);
289
290 let fmt_writer = FmtWriter { f, error: None };
291 let mut io_writer = IoWriter { inner: fmt_writer };
292
293 if report.finish().write(cache, &mut io_writer).is_err() {
294 return write!(f, "Error formatting with ariadne");
295 }
296
297 if io_writer.inner.error.is_some() {
299 return write!(f, "Error writing ariadne output to fmt::Formatter");
300 }
301
302 Ok(())
303 }
304}
305
306impl core::error::Error for DeserError<'_> {}