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 JsonError {
33 pub const fn new(kind: JsonErrorKind, span: Span) -> Self {
35 JsonError {
36 kind,
37 span: Some(span),
38 source_code: None,
39 }
40 }
41
42 pub const fn without_span(kind: JsonErrorKind) -> Self {
44 JsonError {
45 kind,
46 span: None,
47 source_code: None,
48 }
49 }
50
51 pub fn with_source(mut self, source: &str) -> Self {
53 self.source_code = Some(source.to_string());
54 self
55 }
56}
57
58#[derive(Debug)]
60pub enum JsonErrorKind {
61 Scan(ScanErrorKind),
63 ScanWithContext {
65 error: ScanErrorKind,
67 expected_type: &'static str,
69 },
70 UnexpectedToken {
72 got: String,
74 expected: &'static str,
76 },
77 UnexpectedEof {
79 expected: &'static str,
81 },
82 TypeMismatch {
84 expected: &'static str,
86 got: &'static str,
88 },
89 UnknownField {
91 field: String,
93 expected: Vec<&'static str>,
95 suggestion: Option<&'static str>,
97 },
98 MissingField {
100 field: &'static str,
102 object_start: Option<Span>,
104 object_end: Option<Span>,
106 },
107 InvalidValue {
109 message: String,
111 },
112 Reflect(ReflectError),
114 NumberOutOfRange {
116 value: String,
118 target_type: &'static str,
120 },
121 DuplicateKey {
123 key: String,
125 },
126 InvalidUtf8,
128 Solver(String),
130 Io(String),
132}
133
134impl Display for JsonErrorKind {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match self {
137 JsonErrorKind::Scan(e) => write!(f, "{e:?}"),
138 JsonErrorKind::ScanWithContext {
139 error,
140 expected_type,
141 } => {
142 write!(f, "{error:?} (while parsing {expected_type})")
143 }
144 JsonErrorKind::UnexpectedToken { got, expected } => {
145 write!(f, "unexpected token: got {got}, expected {expected}")
146 }
147 JsonErrorKind::UnexpectedEof { expected } => {
148 write!(f, "unexpected end of input, expected {expected}")
149 }
150 JsonErrorKind::TypeMismatch { expected, got } => {
151 write!(f, "type mismatch: expected {expected}, got {got}")
152 }
153 JsonErrorKind::UnknownField {
154 field,
155 expected,
156 suggestion,
157 } => {
158 write!(f, "unknown field `{field}`, expected one of: {expected:?}")?;
159 if let Some(suggested) = suggestion {
160 write!(f, " (did you mean `{suggested}`?)")?;
161 }
162 Ok(())
163 }
164 JsonErrorKind::MissingField { field, .. } => {
165 write!(f, "missing required field `{field}`")
166 }
167 JsonErrorKind::InvalidValue { message } => {
168 write!(f, "invalid value: {message}")
169 }
170 JsonErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
171 JsonErrorKind::NumberOutOfRange { value, target_type } => {
172 write!(f, "number `{value}` out of range for {target_type}")
173 }
174 JsonErrorKind::DuplicateKey { key } => {
175 write!(f, "duplicate key `{key}`")
176 }
177 JsonErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 sequence"),
178 JsonErrorKind::Solver(msg) => write!(f, "solver error: {msg}"),
179 JsonErrorKind::Io(msg) => write!(f, "I/O error: {msg}"),
180 }
181 }
182}
183
184impl JsonErrorKind {
185 pub const fn code(&self) -> &'static str {
187 match self {
188 JsonErrorKind::Scan(_) => "json::scan",
189 JsonErrorKind::ScanWithContext { .. } => "json::scan",
190 JsonErrorKind::UnexpectedToken { .. } => "json::unexpected_token",
191 JsonErrorKind::UnexpectedEof { .. } => "json::unexpected_eof",
192 JsonErrorKind::TypeMismatch { .. } => "json::type_mismatch",
193 JsonErrorKind::UnknownField { .. } => "json::unknown_field",
194 JsonErrorKind::MissingField { .. } => "json::missing_field",
195 JsonErrorKind::InvalidValue { .. } => "json::invalid_value",
196 JsonErrorKind::Reflect(_) => "json::reflect",
197 JsonErrorKind::NumberOutOfRange { .. } => "json::number_out_of_range",
198 JsonErrorKind::DuplicateKey { .. } => "json::duplicate_key",
199 JsonErrorKind::InvalidUtf8 => "json::invalid_utf8",
200 JsonErrorKind::Solver(_) => "json::solver",
201 JsonErrorKind::Io(_) => "json::io",
202 }
203 }
204
205 pub fn label(&self) -> String {
207 match self {
208 JsonErrorKind::Scan(e) => match e {
209 ScanErrorKind::UnexpectedChar(c) => format!("unexpected '{c}'"),
210 ScanErrorKind::UnexpectedEof(ctx) => format!("unexpected end of input {ctx}"),
211 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
212 },
213 JsonErrorKind::ScanWithContext {
214 error,
215 expected_type,
216 } => match error {
217 ScanErrorKind::UnexpectedChar(c) => {
218 format!("unexpected '{c}', expected {expected_type}")
219 }
220 ScanErrorKind::UnexpectedEof(_) => {
221 format!("unexpected end of input, expected {expected_type}")
222 }
223 ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
224 },
225 JsonErrorKind::UnexpectedToken { got, expected } => {
226 format!("expected {expected}, got '{got}'")
227 }
228 JsonErrorKind::UnexpectedEof { expected } => format!("expected {expected}"),
229 JsonErrorKind::TypeMismatch { expected, got } => {
230 format!("expected {expected}, got {got}")
231 }
232 JsonErrorKind::UnknownField {
233 field, suggestion, ..
234 } => {
235 if let Some(suggested) = suggestion {
236 format!("unknown field '{field}' - did you mean '{suggested}'?")
237 } else {
238 format!("unknown field '{field}'")
239 }
240 }
241 JsonErrorKind::MissingField { field, .. } => format!("missing field '{field}'"),
242 JsonErrorKind::InvalidValue { .. } => "invalid value".into(),
243 JsonErrorKind::Reflect(_) => "reflection error".into(),
244 JsonErrorKind::NumberOutOfRange { target_type, .. } => {
245 format!("out of range for {target_type}")
246 }
247 JsonErrorKind::DuplicateKey { key } => format!("duplicate key '{key}'"),
248 JsonErrorKind::InvalidUtf8 => "invalid UTF-8".into(),
249 JsonErrorKind::Solver(_) => "solver error".into(),
250 JsonErrorKind::Io(_) => "I/O error".into(),
251 }
252 }
253}
254
255impl From<AdapterError> for JsonError {
256 fn from(err: AdapterError) -> Self {
257 let kind = match err.kind {
258 AdapterErrorKind::Scan(scan_err) => JsonErrorKind::Scan(scan_err),
259 AdapterErrorKind::NeedMore => JsonErrorKind::UnexpectedEof {
260 expected: "more data",
261 },
262 };
263 JsonError {
264 kind,
265 span: Some(err.span),
266 source_code: None,
267 }
268 }
269}
270
271impl From<ReflectError> for JsonError {
272 fn from(err: ReflectError) -> Self {
273 JsonError {
274 kind: JsonErrorKind::Reflect(err),
275 span: None,
276 source_code: None,
277 }
278 }
279}
280
281#[allow(dead_code)]
283pub type Result<T> = core::result::Result<T, JsonError>;