1use alloc::string::String;
4use alloc::vec::Vec;
5use core::fmt;
6
7#[non_exhaustive]
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum JsonLimitKind {
13 InputBytes,
15 Depth,
17 StringBytes,
19 KeyBytes,
21 NumberBytes,
23 ArrayItems,
25 ObjectMembers,
27 TotalNodes,
29 TotalDecodedStringBytes,
31}
32
33impl JsonLimitKind {
34 pub const fn as_str(self) -> &'static str {
36 match self {
37 Self::InputBytes => "input bytes",
38 Self::Depth => "nesting depth",
39 Self::StringBytes => "string bytes",
40 Self::KeyBytes => "key bytes",
41 Self::NumberBytes => "number bytes",
42 Self::ArrayItems => "array items",
43 Self::ObjectMembers => "object members",
44 Self::TotalNodes => "total nodes",
45 Self::TotalDecodedStringBytes => "total decoded string bytes",
46 }
47 }
48}
49
50#[non_exhaustive]
58#[derive(Debug, Clone, PartialEq, Eq)]
59pub enum JsonErrorKind {
60 UnexpectedEof,
62 UnexpectedByte,
64 InvalidUtf8,
66 InvalidEscape,
68 InvalidUnicodeEscape,
70 LoneSurrogate,
72 UnescapedControlCharacter,
74 InvalidNumber,
76 DuplicateKey,
78 TrailingData,
80 LimitExceeded(JsonLimitKind),
82 WriteFailure,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
88pub enum JsonPathSegment {
89 Key(String),
91 Index(usize),
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Default)]
98pub struct JsonPath {
99 segments: Vec<JsonPathSegment>,
100}
101
102impl JsonPath {
103 pub(crate) fn from_segments(segments: Vec<JsonPathSegment>) -> Self {
104 Self { segments }
105 }
106
107 pub fn segments(&self) -> &[JsonPathSegment] {
109 &self.segments
110 }
111}
112
113impl fmt::Display for JsonPath {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.write_str("$")?;
116 for segment in &self.segments {
117 match segment {
118 JsonPathSegment::Key(key) => write!(f, ".{key}")?,
119 JsonPathSegment::Index(index) => write!(f, "[{index}]")?,
120 }
121 }
122 Ok(())
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
131pub struct JsonError {
132 kind: JsonErrorKind,
133 offset: usize,
134 line: usize,
135 column: usize,
136 path: Option<JsonPath>,
137}
138
139impl JsonError {
140 pub(crate) fn new(kind: JsonErrorKind, offset: usize, line: usize, column: usize) -> Self {
141 Self {
142 kind,
143 offset,
144 line,
145 column,
146 path: None,
147 }
148 }
149
150 pub(crate) fn with_path(mut self, path: JsonPath) -> Self {
151 self.path = Some(path);
152 self
153 }
154
155 pub fn kind(&self) -> &JsonErrorKind {
157 &self.kind
158 }
159
160 pub fn offset(&self) -> usize {
162 self.offset
163 }
164
165 pub fn line(&self) -> usize {
167 self.line
168 }
169
170 pub fn column(&self) -> usize {
172 self.column
173 }
174
175 pub fn path(&self) -> Option<&JsonPath> {
177 self.path.as_ref()
178 }
179}
180
181impl fmt::Display for JsonError {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 let message = match &self.kind {
184 JsonErrorKind::UnexpectedEof => "unexpected end of input",
185 JsonErrorKind::UnexpectedByte => "unexpected byte",
186 JsonErrorKind::InvalidUtf8 => "invalid UTF-8",
187 JsonErrorKind::InvalidEscape => "invalid escape sequence",
188 JsonErrorKind::InvalidUnicodeEscape => "invalid unicode escape",
189 JsonErrorKind::LoneSurrogate => "unpaired UTF-16 surrogate",
190 JsonErrorKind::UnescapedControlCharacter => "unescaped control character in string",
191 JsonErrorKind::InvalidNumber => "invalid number",
192 JsonErrorKind::DuplicateKey => "duplicate object key",
193 JsonErrorKind::TrailingData => "trailing data after JSON value",
194 JsonErrorKind::LimitExceeded(limit) => {
195 write!(
196 f,
197 "limit exceeded: {} at byte {}, line {}, column {}",
198 limit.as_str(),
199 self.offset,
200 self.line,
201 self.column
202 )?;
203 if let Some(path) = &self.path {
204 write!(f, ", path: {path}")?;
205 }
206 return Ok(());
207 }
208 JsonErrorKind::WriteFailure => "failed to write output",
209 };
210 write!(
211 f,
212 "{message} at byte {}, line {}, column {}",
213 self.offset, self.line, self.column
214 )?;
215 if let Some(path) = &self.path {
216 write!(f, ", path: {path}")?;
217 }
218 Ok(())
219 }
220}
221
222#[cfg(feature = "std")]
223impl std::error::Error for JsonError {}
224
225#[non_exhaustive]
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
230pub enum JsonNumberError {
231 OutOfRange,
233 NotAnInteger,
235 NotFinite,
237 InvalidNumber,
239}
240
241impl fmt::Display for JsonNumberError {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 f.write_str(match self {
244 Self::OutOfRange => "number out of range for target type",
245 Self::NotAnInteger => "number is not an integer",
246 Self::NotFinite => "number is not finite",
247 Self::InvalidNumber => "not a valid JSON number",
248 })
249 }
250}
251
252#[cfg(feature = "std")]
253impl std::error::Error for JsonNumberError {}