1use alloc::format;
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6use core::fmt::{self, Display};
7
8use facet_reflect::{ReflectError, Span};
9
10use crate::adapter::{AdapterError, AdapterErrorKind};
11use crate::scanner::ScanErrorKind;
12
13#[derive(Debug)]
15pub struct JsonError {
16 pub kind: JsonErrorKind,
18 pub span: Option<Span>,
20 pub source_code: Option<String>,
22}
23
24impl Display for JsonError {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "{}", self.kind)
27 }
28}
29
30impl std::error::Error for JsonError {}
31
32impl miette::Diagnostic for JsonError {
33 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
34 Some(Box::new(self.kind.code()))
35 }
36
37 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
38 self.source_code
39 .as_ref()
40 .map(|s| s as &dyn miette::SourceCode)
41 }
42
43 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
44 if let JsonErrorKind::MissingField {
46 field,
47 object_start,
48 object_end,
49 } = &self.kind
50 {
51 let mut labels = Vec::new();
52 if let Some(start) = object_start {
53 labels.push(miette::LabeledSpan::new(
54 Some("object started here".into()),
55 start.offset,
56 start.len,
57 ));
58 }
59 if let Some(end) = object_end {
60 labels.push(miette::LabeledSpan::new(
61 Some(format!("object ended without field `{field}`")),
62 end.offset,
63 end.len,
64 ));
65 }
66 if labels.is_empty() {
67 return None;
68 }
69 return Some(Box::new(labels.into_iter()));
70 }
71
72 let span = self.span?;
74 Some(Box::new(core::iter::once(miette::LabeledSpan::new(
75 Some(self.kind.label()),
76 span.offset,
77 span.len,
78 ))))
79 }
80}
81
82impl JsonError {
83 pub fn new(kind: JsonErrorKind, span: Span) -> Self {
85 JsonError {
86 kind,
87 span: Some(span),
88 source_code: None,
89 }
90 }
91
92 pub fn without_span(kind: JsonErrorKind) -> Self {
94 JsonError {
95 kind,
96 span: None,
97 source_code: None,
98 }
99 }
100
101 pub fn with_source(mut self, source: &str) -> Self {
103 self.source_code = Some(source.to_string());
104 self
105 }
106}
107
108#[derive(Debug)]
110pub enum JsonErrorKind {
111 Scan(ScanErrorKind),
113 ScanWithContext {
115 error: ScanErrorKind,
117 expected_type: &'static str,
119 },
120 UnexpectedToken {
122 got: String,
124 expected: &'static str,
126 },
127 UnexpectedEof {
129 expected: &'static str,
131 },
132 TypeMismatch {
134 expected: &'static str,
136 got: &'static str,
138 },
139 UnknownField {
141 field: String,
143 expected: Vec<&'static str>,
145 suggestion: Option<&'static str>,
147 },
148 MissingField {
150 field: &'static str,
152 object_start: Option<Span>,
154 object_end: Option<Span>,
156 },
157 InvalidValue {
159 message: String,
161 },
162 Reflect(ReflectError),
164 NumberOutOfRange {
166 value: String,
168 target_type: &'static str,
170 },
171 DuplicateKey {
173 key: String,
175 },
176 InvalidUtf8,
178 Solver(String),
180 Io(String),
182}
183
184impl Display for JsonErrorKind {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 match self {
187 JsonErrorKind::Scan(e) => write!(f, "{e:?}"),
188 JsonErrorKind::ScanWithContext {
189 error,
190 expected_type,
191 } => {
192 write!(f, "{error:?} (while parsing {expected_type})")
193 }
194 JsonErrorKind::UnexpectedToken { got, expected } => {
195 write!(f, "unexpected token: got {got}, expected {expected}")
196 }
197 JsonErrorKind::UnexpectedEof { expected } => {
198 write!(f, "unexpected end of input, expected {expected}")
199 }
200 JsonErrorKind::TypeMismatch { expected, got } => {
201 write!(f, "type mismatch: expected {expected}, got {got}")
202 }
203 JsonErrorKind::UnknownField {
204 field,
205 expected,
206 suggestion,
207 } => {
208 write!(f, "unknown field `{field}`, expected one of: {expected:?}")?;
209 if let Some(suggested) = suggestion {
210 write!(f, " (did you mean `{suggested}`?)")?;
211 }
212 Ok(())
213 }
214 JsonErrorKind::MissingField { field, .. } => {
215 write!(f, "missing required field `{field}`")
216 }
217 JsonErrorKind::InvalidValue { message } => {
218 write!(f, "invalid value: {message}")
219 }
220 JsonErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
221 JsonErrorKind::NumberOutOfRange { value, target_type } => {
222 write!(f, "number `{value}` out of range for {target_type}")
223 }
224 JsonErrorKind::DuplicateKey { key } => {
225 write!(f, "duplicate key `{key}`")
226 }
227 JsonErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 sequence"),
228 JsonErrorKind::Solver(msg) => write!(f, "solver error: {msg}"),
229 JsonErrorKind::Io(msg) => write!(f, "I/O error: {msg}"),
230 }
231 }
232}
233
234impl JsonErrorKind {
235 pub fn code(&self) -> &'static str {
237 match self {
238 JsonErrorKind::Scan(_) => "json::scan",
239 JsonErrorKind::ScanWithContext { .. } => "json::scan",
240 JsonErrorKind::UnexpectedToken { .. } => "json::unexpected_token",
241 JsonErrorKind::UnexpectedEof { .. } => "json::unexpected_eof",
242 JsonErrorKind::TypeMismatch { .. } => "json::type_mismatch",
243 JsonErrorKind::UnknownField { .. } => "json::unknown_field",
244 JsonErrorKind::MissingField { .. } => "json::missing_field",
245 JsonErrorKind::InvalidValue { .. } => "json::invalid_value",
246 JsonErrorKind::Reflect(_) => "json::reflect",
247 JsonErrorKind::NumberOutOfRange { .. } => "json::number_out_of_range",
248 JsonErrorKind::DuplicateKey { .. } => "json::duplicate_key",
249 JsonErrorKind::InvalidUtf8 => "json::invalid_utf8",
250 JsonErrorKind::Solver(_) => "json::solver",
251 JsonErrorKind::Io(_) => "json::io",
252 }
253 }
254
255 pub fn label(&self) -> String {
257 match self {
258 JsonErrorKind::Scan(e) => match e {
259 ScanErrorKind::UnexpectedChar(c) => format!("unexpected '{c}'"),
260 ScanErrorKind::UnexpectedEof(ctx) => format!("unexpected end of input {ctx}"),
261 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
262 },
263 JsonErrorKind::ScanWithContext {
264 error,
265 expected_type,
266 } => match error {
267 ScanErrorKind::UnexpectedChar(c) => {
268 format!("unexpected '{c}', expected {expected_type}")
269 }
270 ScanErrorKind::UnexpectedEof(_) => {
271 format!("unexpected end of input, expected {expected_type}")
272 }
273 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
274 },
275 JsonErrorKind::UnexpectedToken { got, expected } => {
276 format!("expected {expected}, got '{got}'")
277 }
278 JsonErrorKind::UnexpectedEof { expected } => format!("expected {expected}"),
279 JsonErrorKind::TypeMismatch { expected, got } => {
280 format!("expected {expected}, got {got}")
281 }
282 JsonErrorKind::UnknownField {
283 field, suggestion, ..
284 } => {
285 if let Some(suggested) = suggestion {
286 format!("unknown field '{field}' - did you mean '{suggested}'?")
287 } else {
288 format!("unknown field '{field}'")
289 }
290 }
291 JsonErrorKind::MissingField { field, .. } => format!("missing field '{field}'"),
292 JsonErrorKind::InvalidValue { .. } => "invalid value".into(),
293 JsonErrorKind::Reflect(_) => "reflection error".into(),
294 JsonErrorKind::NumberOutOfRange { target_type, .. } => {
295 format!("out of range for {target_type}")
296 }
297 JsonErrorKind::DuplicateKey { key } => format!("duplicate key '{key}'"),
298 JsonErrorKind::InvalidUtf8 => "invalid UTF-8".into(),
299 JsonErrorKind::Solver(_) => "solver error".into(),
300 JsonErrorKind::Io(_) => "I/O error".into(),
301 }
302 }
303}
304
305impl From<AdapterError> for JsonError {
306 fn from(err: AdapterError) -> Self {
307 let kind = match err.kind {
308 AdapterErrorKind::Scan(scan_err) => JsonErrorKind::Scan(scan_err),
309 AdapterErrorKind::NeedMore => JsonErrorKind::UnexpectedEof {
310 expected: "more data",
311 },
312 };
313 JsonError {
314 kind,
315 span: Some(err.span),
316 source_code: None,
317 }
318 }
319}
320
321impl From<ReflectError> for JsonError {
322 fn from(err: ReflectError) -> Self {
323 JsonError {
324 kind: JsonErrorKind::Reflect(err),
325 span: None,
326 source_code: None,
327 }
328 }
329}
330
331#[allow(dead_code)]
333pub type Result<T> = core::result::Result<T, JsonError>;