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
32#[cfg(feature = "miette")]
33impl miette::Diagnostic for JsonError {
34 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
35 Some(Box::new(self.kind.code()))
36 }
37
38 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
39 self.source_code
40 .as_ref()
41 .map(|s| s as &dyn miette::SourceCode)
42 }
43
44 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
45 if let JsonErrorKind::MissingField {
47 field,
48 object_start,
49 object_end,
50 } = &self.kind
51 {
52 let mut labels = Vec::new();
53 if let Some(start) = object_start {
54 labels.push(miette::LabeledSpan::new(
55 Some("object started here".into()),
56 start.offset,
57 start.len,
58 ));
59 }
60 if let Some(end) = object_end {
61 labels.push(miette::LabeledSpan::new(
62 Some(format!("object ended without field `{field}`")),
63 end.offset,
64 end.len,
65 ));
66 }
67 if labels.is_empty() {
68 return None;
69 }
70 return Some(Box::new(labels.into_iter()));
71 }
72
73 let span = self.span?;
75 Some(Box::new(core::iter::once(miette::LabeledSpan::new(
76 Some(self.kind.label()),
77 span.offset,
78 span.len,
79 ))))
80 }
81}
82
83impl JsonError {
84 pub fn new(kind: JsonErrorKind, span: Span) -> Self {
86 JsonError {
87 kind,
88 span: Some(span),
89 source_code: None,
90 }
91 }
92
93 pub fn without_span(kind: JsonErrorKind) -> Self {
95 JsonError {
96 kind,
97 span: None,
98 source_code: None,
99 }
100 }
101
102 pub fn with_source(mut self, source: &str) -> Self {
104 self.source_code = Some(source.to_string());
105 self
106 }
107}
108
109#[derive(Debug)]
111pub enum JsonErrorKind {
112 Scan(ScanErrorKind),
114 ScanWithContext {
116 error: ScanErrorKind,
118 expected_type: &'static str,
120 },
121 UnexpectedToken {
123 got: String,
125 expected: &'static str,
127 },
128 UnexpectedEof {
130 expected: &'static str,
132 },
133 TypeMismatch {
135 expected: &'static str,
137 got: &'static str,
139 },
140 UnknownField {
142 field: String,
144 expected: Vec<&'static str>,
146 suggestion: Option<&'static str>,
148 },
149 MissingField {
151 field: &'static str,
153 object_start: Option<Span>,
155 object_end: Option<Span>,
157 },
158 InvalidValue {
160 message: String,
162 },
163 Reflect(ReflectError),
165 NumberOutOfRange {
167 value: String,
169 target_type: &'static str,
171 },
172 DuplicateKey {
174 key: String,
176 },
177 InvalidUtf8,
179 Solver(String),
181 Io(String),
183}
184
185impl Display for JsonErrorKind {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 match self {
188 JsonErrorKind::Scan(e) => write!(f, "{e:?}"),
189 JsonErrorKind::ScanWithContext {
190 error,
191 expected_type,
192 } => {
193 write!(f, "{error:?} (while parsing {expected_type})")
194 }
195 JsonErrorKind::UnexpectedToken { got, expected } => {
196 write!(f, "unexpected token: got {got}, expected {expected}")
197 }
198 JsonErrorKind::UnexpectedEof { expected } => {
199 write!(f, "unexpected end of input, expected {expected}")
200 }
201 JsonErrorKind::TypeMismatch { expected, got } => {
202 write!(f, "type mismatch: expected {expected}, got {got}")
203 }
204 JsonErrorKind::UnknownField {
205 field,
206 expected,
207 suggestion,
208 } => {
209 write!(f, "unknown field `{field}`, expected one of: {expected:?}")?;
210 if let Some(suggested) = suggestion {
211 write!(f, " (did you mean `{suggested}`?)")?;
212 }
213 Ok(())
214 }
215 JsonErrorKind::MissingField { field, .. } => {
216 write!(f, "missing required field `{field}`")
217 }
218 JsonErrorKind::InvalidValue { message } => {
219 write!(f, "invalid value: {message}")
220 }
221 JsonErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
222 JsonErrorKind::NumberOutOfRange { value, target_type } => {
223 write!(f, "number `{value}` out of range for {target_type}")
224 }
225 JsonErrorKind::DuplicateKey { key } => {
226 write!(f, "duplicate key `{key}`")
227 }
228 JsonErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 sequence"),
229 JsonErrorKind::Solver(msg) => write!(f, "solver error: {msg}"),
230 JsonErrorKind::Io(msg) => write!(f, "I/O error: {msg}"),
231 }
232 }
233}
234
235impl JsonErrorKind {
236 pub fn code(&self) -> &'static str {
238 match self {
239 JsonErrorKind::Scan(_) => "json::scan",
240 JsonErrorKind::ScanWithContext { .. } => "json::scan",
241 JsonErrorKind::UnexpectedToken { .. } => "json::unexpected_token",
242 JsonErrorKind::UnexpectedEof { .. } => "json::unexpected_eof",
243 JsonErrorKind::TypeMismatch { .. } => "json::type_mismatch",
244 JsonErrorKind::UnknownField { .. } => "json::unknown_field",
245 JsonErrorKind::MissingField { .. } => "json::missing_field",
246 JsonErrorKind::InvalidValue { .. } => "json::invalid_value",
247 JsonErrorKind::Reflect(_) => "json::reflect",
248 JsonErrorKind::NumberOutOfRange { .. } => "json::number_out_of_range",
249 JsonErrorKind::DuplicateKey { .. } => "json::duplicate_key",
250 JsonErrorKind::InvalidUtf8 => "json::invalid_utf8",
251 JsonErrorKind::Solver(_) => "json::solver",
252 JsonErrorKind::Io(_) => "json::io",
253 }
254 }
255
256 pub fn label(&self) -> String {
258 match self {
259 JsonErrorKind::Scan(e) => match e {
260 ScanErrorKind::UnexpectedChar(c) => format!("unexpected '{c}'"),
261 ScanErrorKind::UnexpectedEof(ctx) => format!("unexpected end of input {ctx}"),
262 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
263 },
264 JsonErrorKind::ScanWithContext {
265 error,
266 expected_type,
267 } => match error {
268 ScanErrorKind::UnexpectedChar(c) => {
269 format!("unexpected '{c}', expected {expected_type}")
270 }
271 ScanErrorKind::UnexpectedEof(_) => {
272 format!("unexpected end of input, expected {expected_type}")
273 }
274 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
275 },
276 JsonErrorKind::UnexpectedToken { got, expected } => {
277 format!("expected {expected}, got '{got}'")
278 }
279 JsonErrorKind::UnexpectedEof { expected } => format!("expected {expected}"),
280 JsonErrorKind::TypeMismatch { expected, got } => {
281 format!("expected {expected}, got {got}")
282 }
283 JsonErrorKind::UnknownField {
284 field, suggestion, ..
285 } => {
286 if let Some(suggested) = suggestion {
287 format!("unknown field '{field}' - did you mean '{suggested}'?")
288 } else {
289 format!("unknown field '{field}'")
290 }
291 }
292 JsonErrorKind::MissingField { field, .. } => format!("missing field '{field}'"),
293 JsonErrorKind::InvalidValue { .. } => "invalid value".into(),
294 JsonErrorKind::Reflect(_) => "reflection error".into(),
295 JsonErrorKind::NumberOutOfRange { target_type, .. } => {
296 format!("out of range for {target_type}")
297 }
298 JsonErrorKind::DuplicateKey { key } => format!("duplicate key '{key}'"),
299 JsonErrorKind::InvalidUtf8 => "invalid UTF-8".into(),
300 JsonErrorKind::Solver(_) => "solver error".into(),
301 JsonErrorKind::Io(_) => "I/O error".into(),
302 }
303 }
304}
305
306impl From<AdapterError> for JsonError {
307 fn from(err: AdapterError) -> Self {
308 let kind = match err.kind {
309 AdapterErrorKind::Scan(scan_err) => JsonErrorKind::Scan(scan_err),
310 AdapterErrorKind::NeedMore => JsonErrorKind::UnexpectedEof {
311 expected: "more data",
312 },
313 };
314 JsonError {
315 kind,
316 span: Some(err.span),
317 source_code: None,
318 }
319 }
320}
321
322impl From<ReflectError> for JsonError {
323 fn from(err: ReflectError) -> Self {
324 JsonError {
325 kind: JsonErrorKind::Reflect(err),
326 span: None,
327 source_code: None,
328 }
329 }
330}
331
332#[allow(dead_code)]
334pub type Result<T> = core::result::Result<T, JsonError>;