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::scanner::ScanErrorKind;
11
12#[derive(Debug)]
14pub struct JsonError {
15 pub kind: JsonErrorKind,
17 pub span: Option<Span>,
19 pub source_code: Option<String>,
21}
22
23impl Display for JsonError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "{}", self.kind)
26 }
27}
28
29impl std::error::Error for JsonError {}
30
31impl JsonError {
32 pub const fn new(kind: JsonErrorKind, span: Span) -> Self {
34 JsonError {
35 kind,
36 span: Some(span),
37 source_code: None,
38 }
39 }
40
41 pub const fn without_span(kind: JsonErrorKind) -> Self {
43 JsonError {
44 kind,
45 span: None,
46 source_code: None,
47 }
48 }
49
50 pub fn with_source(mut self, source: &str) -> Self {
52 self.source_code = Some(source.to_string());
53 self
54 }
55}
56
57#[derive(Debug)]
59pub enum JsonErrorKind {
60 Scan(ScanErrorKind),
62 ScanWithContext {
64 error: ScanErrorKind,
66 expected_type: &'static str,
68 },
69 UnexpectedToken {
71 got: String,
73 expected: &'static str,
75 },
76 UnexpectedEof {
78 expected: &'static str,
80 },
81 TypeMismatch {
83 expected: &'static str,
85 got: &'static str,
87 },
88 UnknownField {
90 field: String,
92 expected: Vec<&'static str>,
94 suggestion: Option<&'static str>,
96 },
97 MissingField {
99 field: &'static str,
101 object_start: Option<Span>,
103 object_end: Option<Span>,
105 },
106 InvalidValue {
108 message: String,
110 },
111 Reflect(ReflectError),
113 NumberOutOfRange {
115 value: String,
117 target_type: &'static str,
119 },
120 DuplicateKey {
122 key: String,
124 },
125 InvalidUtf8,
127 Solver(String),
129 Io(String),
131}
132
133impl Display for JsonErrorKind {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 JsonErrorKind::Scan(e) => write!(f, "{e:?}"),
137 JsonErrorKind::ScanWithContext {
138 error,
139 expected_type,
140 } => {
141 write!(f, "{error:?} (while parsing {expected_type})")
142 }
143 JsonErrorKind::UnexpectedToken { got, expected } => {
144 write!(f, "unexpected token: got {got}, expected {expected}")
145 }
146 JsonErrorKind::UnexpectedEof { expected } => {
147 write!(f, "unexpected end of input, expected {expected}")
148 }
149 JsonErrorKind::TypeMismatch { expected, got } => {
150 write!(f, "type mismatch: expected {expected}, got {got}")
151 }
152 JsonErrorKind::UnknownField {
153 field,
154 expected,
155 suggestion,
156 } => {
157 write!(f, "unknown field `{field}`, expected one of: {expected:?}")?;
158 if let Some(suggested) = suggestion {
159 write!(f, " (did you mean `{suggested}`?)")?;
160 }
161 Ok(())
162 }
163 JsonErrorKind::MissingField { field, .. } => {
164 write!(f, "missing required field `{field}`")
165 }
166 JsonErrorKind::InvalidValue { message } => {
167 write!(f, "invalid value: {message}")
168 }
169 JsonErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
170 JsonErrorKind::NumberOutOfRange { value, target_type } => {
171 write!(f, "number `{value}` out of range for {target_type}")
172 }
173 JsonErrorKind::DuplicateKey { key } => {
174 write!(f, "duplicate key `{key}`")
175 }
176 JsonErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 sequence"),
177 JsonErrorKind::Solver(msg) => write!(f, "solver error: {msg}"),
178 JsonErrorKind::Io(msg) => write!(f, "I/O error: {msg}"),
179 }
180 }
181}
182
183impl JsonErrorKind {
184 pub const fn code(&self) -> &'static str {
186 match self {
187 JsonErrorKind::Scan(_) => "json::scan",
188 JsonErrorKind::ScanWithContext { .. } => "json::scan",
189 JsonErrorKind::UnexpectedToken { .. } => "json::unexpected_token",
190 JsonErrorKind::UnexpectedEof { .. } => "json::unexpected_eof",
191 JsonErrorKind::TypeMismatch { .. } => "json::type_mismatch",
192 JsonErrorKind::UnknownField { .. } => "json::unknown_field",
193 JsonErrorKind::MissingField { .. } => "json::missing_field",
194 JsonErrorKind::InvalidValue { .. } => "json::invalid_value",
195 JsonErrorKind::Reflect(_) => "json::reflect",
196 JsonErrorKind::NumberOutOfRange { .. } => "json::number_out_of_range",
197 JsonErrorKind::DuplicateKey { .. } => "json::duplicate_key",
198 JsonErrorKind::InvalidUtf8 => "json::invalid_utf8",
199 JsonErrorKind::Solver(_) => "json::solver",
200 JsonErrorKind::Io(_) => "json::io",
201 }
202 }
203
204 pub fn label(&self) -> String {
206 match self {
207 JsonErrorKind::Scan(e) => match e {
208 ScanErrorKind::UnexpectedChar(c) => format!("unexpected '{c}'"),
209 ScanErrorKind::UnexpectedEof(ctx) => format!("unexpected end of input {ctx}"),
210 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
211 },
212 JsonErrorKind::ScanWithContext {
213 error,
214 expected_type,
215 } => match error {
216 ScanErrorKind::UnexpectedChar(c) => {
217 format!("unexpected '{c}', expected {expected_type}")
218 }
219 ScanErrorKind::UnexpectedEof(_) => {
220 format!("unexpected end of input, expected {expected_type}")
221 }
222 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
223 },
224 JsonErrorKind::UnexpectedToken { got, expected } => {
225 format!("expected {expected}, got '{got}'")
226 }
227 JsonErrorKind::UnexpectedEof { expected } => format!("expected {expected}"),
228 JsonErrorKind::TypeMismatch { expected, got } => {
229 format!("expected {expected}, got {got}")
230 }
231 JsonErrorKind::UnknownField {
232 field, suggestion, ..
233 } => {
234 if let Some(suggested) = suggestion {
235 format!("unknown field '{field}' - did you mean '{suggested}'?")
236 } else {
237 format!("unknown field '{field}'")
238 }
239 }
240 JsonErrorKind::MissingField { field, .. } => format!("missing field '{field}'"),
241 JsonErrorKind::InvalidValue { .. } => "invalid value".into(),
242 JsonErrorKind::Reflect(_) => "reflection error".into(),
243 JsonErrorKind::NumberOutOfRange { target_type, .. } => {
244 format!("out of range for {target_type}")
245 }
246 JsonErrorKind::DuplicateKey { key } => format!("duplicate key '{key}'"),
247 JsonErrorKind::InvalidUtf8 => "invalid UTF-8".into(),
248 JsonErrorKind::Solver(_) => "solver error".into(),
249 JsonErrorKind::Io(_) => "I/O error".into(),
250 }
251 }
252}
253
254impl From<ReflectError> for JsonError {
255 fn from(err: ReflectError) -> Self {
256 JsonError {
257 kind: JsonErrorKind::Reflect(err),
258 span: None,
259 source_code: None,
260 }
261 }
262}
263
264#[allow(dead_code)]
266pub type Result<T> = core::result::Result<T, JsonError>;