1use core::{char, fmt, str};
2
3const MAX_DEPTH: usize = 64;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct JsonString<'a> {
7 encoded: &'a str,
8 escaped: bool,
9}
10
11impl<'a> JsonString<'a> {
12 pub const fn encoded(&self) -> &'a str {
13 self.encoded
14 }
15
16 pub fn as_str(&self) -> Option<&'a str> {
17 (!self.escaped).then_some(self.encoded)
18 }
19
20 pub fn decode_into<'buffer>(
21 &self,
22 buffer: &'buffer mut [u8],
23 ) -> Result<&'buffer str, JsonError> {
24 if !self.escaped {
25 let destination = buffer
26 .get_mut(..self.encoded.len())
27 .ok_or(JsonError::BufferTooSmall)?;
28 destination.copy_from_slice(self.encoded.as_bytes());
29 return str::from_utf8(destination).map_err(|_| JsonError::InvalidUtf8);
30 }
31
32 let source = self.encoded.as_bytes();
33 let mut input = 0;
34 let mut output = 0;
35 while input < source.len() {
36 if source[input] != b'\\' {
37 let start = input;
38 while input < source.len() && source[input] != b'\\' {
39 input += 1;
40 }
41 copy_decoded(buffer, &mut output, &source[start..input])?;
42 continue;
43 }
44 let (character, next) = escaped_character(source, input)?;
45 input = next;
46 let mut encoded = [0; 4];
47 copy_decoded(
48 buffer,
49 &mut output,
50 character.encode_utf8(&mut encoded).as_bytes(),
51 )?;
52 }
53 str::from_utf8(&buffer[..output]).map_err(|_| JsonError::InvalidUtf8)
54 }
55
56 pub(crate) fn decoded_eq_ascii(&self, expected: &str) -> bool {
57 if !expected.is_ascii() {
58 return false;
59 }
60 if !self.escaped {
61 return self.encoded == expected;
62 }
63 let source = self.encoded.as_bytes();
64 let expected = expected.as_bytes();
65 let mut input = 0;
66 let mut output = 0;
67 while input < source.len() {
68 if source[input] == b'\\' {
69 let Ok((character, next)) = escaped_character(source, input) else {
70 return false;
71 };
72 if !character.is_ascii() || expected.get(output).copied() != Some(character as u8) {
73 return false;
74 }
75 input = next;
76 output += 1;
77 } else {
78 if expected.get(output).copied() != Some(source[input]) {
79 return false;
80 }
81 input += 1;
82 output += 1;
83 }
84 }
85 output == expected.len()
86 }
87}
88
89#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90pub enum JsonError {
91 InvalidUtf8,
92 InvalidSyntax,
93 NestingTooDeep,
94 InvalidEscape,
95 InvalidNumber,
96 WrongType,
97 MissingField(&'static str),
98 DuplicateField(&'static str),
99 BufferTooSmall,
100}
101
102impl fmt::Display for JsonError {
103 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Self::InvalidUtf8 => formatter.write_str("JSON is not UTF-8"),
106 Self::InvalidSyntax => formatter.write_str("invalid JSON syntax"),
107 Self::NestingTooDeep => formatter.write_str("JSON nesting is too deep"),
108 Self::InvalidEscape => formatter.write_str("invalid JSON string escape"),
109 Self::InvalidNumber => formatter.write_str("invalid JSON number"),
110 Self::WrongType => formatter.write_str("unexpected JSON value type"),
111 Self::MissingField(field) => write!(formatter, "missing JSON field {field}"),
112 Self::DuplicateField(field) => write!(formatter, "duplicate JSON field {field}"),
113 Self::BufferTooSmall => formatter.write_str("JSON string output buffer is too small"),
114 }
115 }
116}
117
118#[derive(Clone, Copy, Debug, Eq, PartialEq)]
119pub(crate) struct Value<'a> {
120 bytes: &'a [u8],
121}
122
123impl<'a> Value<'a> {
124 pub(crate) fn parse_document(bytes: &'a [u8]) -> Result<Self, JsonError> {
125 str::from_utf8(bytes).map_err(|_| JsonError::InvalidUtf8)?;
126 let start = whitespace(bytes, 0);
127 let end = parse_value(bytes, start, 0)?;
128 if whitespace(bytes, end) != bytes.len() {
129 return Err(JsonError::InvalidSyntax);
130 }
131 Ok(Self {
132 bytes: &bytes[start..end],
133 })
134 }
135
136 pub(crate) fn object(self) -> Result<Object<'a>, JsonError> {
137 if self.bytes.first() != Some(&b'{') {
138 return Err(JsonError::WrongType);
139 }
140 Ok(Object { bytes: self.bytes })
141 }
142
143 pub(crate) fn array(self) -> Result<Array<'a>, JsonError> {
144 if self.bytes.first() != Some(&b'[') {
145 return Err(JsonError::WrongType);
146 }
147 Ok(Array { bytes: self.bytes })
148 }
149
150 pub(crate) fn string(self) -> Result<JsonString<'a>, JsonError> {
151 if self.bytes.first() != Some(&b'"') || self.bytes.last() != Some(&b'"') {
152 return Err(JsonError::WrongType);
153 }
154 let encoded = str::from_utf8(&self.bytes[1..self.bytes.len() - 1])
155 .map_err(|_| JsonError::InvalidUtf8)?;
156 Ok(JsonString {
157 encoded,
158 escaped: encoded.as_bytes().contains(&b'\\'),
159 })
160 }
161
162 pub(crate) fn u64(self) -> Result<u64, JsonError> {
163 let value = str::from_utf8(self.bytes).map_err(|_| JsonError::InvalidUtf8)?;
164 if value.is_empty() || !value.bytes().all(|byte| byte.is_ascii_digit()) {
165 return Err(JsonError::WrongType);
166 }
167 value.parse().map_err(|_| JsonError::InvalidNumber)
168 }
169
170 pub(crate) fn is_null(self) -> bool {
171 self.bytes == b"null"
172 }
173}
174
175#[derive(Clone, Copy, Debug, Eq, PartialEq)]
176pub(crate) struct Object<'a> {
177 bytes: &'a [u8],
178}
179
180impl<'a> Object<'a> {
181 pub(crate) fn get(self, name: &'static str) -> Result<Option<Value<'a>>, JsonError> {
182 let mut found = None;
183 for member in self.iter() {
184 let (key, value) = member?;
185 if key.decoded_eq_ascii(name) {
186 if found.is_some() {
187 return Err(JsonError::DuplicateField(name));
188 }
189 found = Some(value);
190 }
191 }
192 Ok(found)
193 }
194
195 pub(crate) fn required(self, name: &'static str) -> Result<Value<'a>, JsonError> {
196 self.get(name)?.ok_or(JsonError::MissingField(name))
197 }
198
199 pub(crate) fn iter(self) -> ObjectIter<'a> {
200 ObjectIter {
201 bytes: self.bytes,
202 position: 1,
203 first: true,
204 finished: false,
205 }
206 }
207}
208
209pub(crate) struct ObjectIter<'a> {
210 bytes: &'a [u8],
211 position: usize,
212 first: bool,
213 finished: bool,
214}
215
216impl<'a> Iterator for ObjectIter<'a> {
217 type Item = Result<(JsonString<'a>, Value<'a>), JsonError>;
218
219 fn next(&mut self) -> Option<Self::Item> {
220 if self.finished {
221 return None;
222 }
223 let result = self.next_inner();
224 if result.is_err() {
225 self.finished = true;
226 }
227 result.transpose()
228 }
229}
230
231impl<'a> ObjectIter<'a> {
232 fn next_inner(&mut self) -> Result<Option<(JsonString<'a>, Value<'a>)>, JsonError> {
233 self.position = whitespace(self.bytes, self.position);
234 if self.bytes.get(self.position) == Some(&b'}') {
235 self.finished = true;
236 return Ok(None);
237 }
238 if !self.first {
239 if self.bytes.get(self.position) != Some(&b',') {
240 return Err(JsonError::InvalidSyntax);
241 }
242 self.position = whitespace(self.bytes, self.position + 1);
243 }
244 self.first = false;
245 if self.bytes.get(self.position) != Some(&b'"') {
246 return Err(JsonError::InvalidSyntax);
247 }
248 let key_end = parse_string(self.bytes, self.position)?;
249 let key = Value {
250 bytes: &self.bytes[self.position..key_end],
251 }
252 .string()?;
253 self.position = whitespace(self.bytes, key_end);
254 if self.bytes.get(self.position) != Some(&b':') {
255 return Err(JsonError::InvalidSyntax);
256 }
257 let start = whitespace(self.bytes, self.position + 1);
258 let end = parse_value(self.bytes, start, 0)?;
259 self.position = end;
260 Ok(Some((
261 key,
262 Value {
263 bytes: &self.bytes[start..end],
264 },
265 )))
266 }
267}
268
269#[derive(Clone, Copy, Debug, Eq, PartialEq)]
270pub(crate) struct Array<'a> {
271 bytes: &'a [u8],
272}
273
274impl<'a> Array<'a> {
275 pub(crate) fn iter(self) -> ArrayIter<'a> {
276 ArrayIter {
277 bytes: self.bytes,
278 position: 1,
279 first: true,
280 finished: false,
281 }
282 }
283}
284
285pub(crate) struct ArrayIter<'a> {
286 bytes: &'a [u8],
287 position: usize,
288 first: bool,
289 finished: bool,
290}
291
292impl<'a> Iterator for ArrayIter<'a> {
293 type Item = Result<Value<'a>, JsonError>;
294
295 fn next(&mut self) -> Option<Self::Item> {
296 if self.finished {
297 return None;
298 }
299 let result = self.next_inner();
300 if result.is_err() {
301 self.finished = true;
302 }
303 result.transpose()
304 }
305}
306
307impl<'a> ArrayIter<'a> {
308 fn next_inner(&mut self) -> Result<Option<Value<'a>>, JsonError> {
309 self.position = whitespace(self.bytes, self.position);
310 if self.bytes.get(self.position) == Some(&b']') {
311 self.finished = true;
312 return Ok(None);
313 }
314 if !self.first {
315 if self.bytes.get(self.position) != Some(&b',') {
316 return Err(JsonError::InvalidSyntax);
317 }
318 self.position = whitespace(self.bytes, self.position + 1);
319 }
320 self.first = false;
321 let start = self.position;
322 let end = parse_value(self.bytes, start, 0)?;
323 self.position = end;
324 Ok(Some(Value {
325 bytes: &self.bytes[start..end],
326 }))
327 }
328}
329
330fn parse_value(bytes: &[u8], position: usize, depth: usize) -> Result<usize, JsonError> {
331 if depth > MAX_DEPTH {
332 return Err(JsonError::NestingTooDeep);
333 }
334 match bytes.get(position).copied() {
335 Some(b'"') => parse_string(bytes, position),
336 Some(b'{') => parse_object(bytes, position, depth + 1),
337 Some(b'[') => parse_array(bytes, position, depth + 1),
338 Some(b't') => literal(bytes, position, b"true"),
339 Some(b'f') => literal(bytes, position, b"false"),
340 Some(b'n') => literal(bytes, position, b"null"),
341 Some(b'-' | b'0'..=b'9') => parse_number(bytes, position),
342 _ => Err(JsonError::InvalidSyntax),
343 }
344}
345
346fn parse_object(bytes: &[u8], mut position: usize, depth: usize) -> Result<usize, JsonError> {
347 position = whitespace(bytes, position + 1);
348 if bytes.get(position) == Some(&b'}') {
349 return Ok(position + 1);
350 }
351 loop {
352 if bytes.get(position) != Some(&b'"') {
353 return Err(JsonError::InvalidSyntax);
354 }
355 position = whitespace(bytes, parse_string(bytes, position)?);
356 if bytes.get(position) != Some(&b':') {
357 return Err(JsonError::InvalidSyntax);
358 }
359 position = whitespace(
360 bytes,
361 parse_value(bytes, whitespace(bytes, position + 1), depth)?,
362 );
363 match bytes.get(position) {
364 Some(b'}') => return Ok(position + 1),
365 Some(b',') => position = whitespace(bytes, position + 1),
366 _ => return Err(JsonError::InvalidSyntax),
367 }
368 }
369}
370
371fn parse_array(bytes: &[u8], mut position: usize, depth: usize) -> Result<usize, JsonError> {
372 position = whitespace(bytes, position + 1);
373 if bytes.get(position) == Some(&b']') {
374 return Ok(position + 1);
375 }
376 loop {
377 position = whitespace(bytes, parse_value(bytes, position, depth)?);
378 match bytes.get(position) {
379 Some(b']') => return Ok(position + 1),
380 Some(b',') => position = whitespace(bytes, position + 1),
381 _ => return Err(JsonError::InvalidSyntax),
382 }
383 }
384}
385
386fn parse_string(bytes: &[u8], position: usize) -> Result<usize, JsonError> {
387 let mut index = position + 1;
388 while let Some(byte) = bytes.get(index).copied() {
389 match byte {
390 b'"' => return Ok(index + 1),
391 b'\\' => {
392 let (_, next) = escaped_character(bytes, index)?;
393 index = next;
394 }
395 0..=0x1f => return Err(JsonError::InvalidSyntax),
396 _ => index += 1,
397 }
398 }
399 Err(JsonError::InvalidSyntax)
400}
401
402fn escaped_character(bytes: &[u8], slash: usize) -> Result<(char, usize), JsonError> {
403 match bytes.get(slash + 1).copied() {
404 Some(b'"') => Ok(('"', slash + 2)),
405 Some(b'\\') => Ok(('\\', slash + 2)),
406 Some(b'/') => Ok(('/', slash + 2)),
407 Some(b'b') => Ok(('\u{0008}', slash + 2)),
408 Some(b'f') => Ok(('\u{000c}', slash + 2)),
409 Some(b'n') => Ok(('\n', slash + 2)),
410 Some(b'r') => Ok(('\r', slash + 2)),
411 Some(b't') => Ok(('\t', slash + 2)),
412 Some(b'u') => {
413 let first = unicode_escape(bytes, slash + 2)?;
414 let next = slash + 6;
415 let scalar = if (0xd800..=0xdbff).contains(&first) {
416 if bytes.get(next..next + 2) != Some(b"\\u") {
417 return Err(JsonError::InvalidEscape);
418 }
419 let second = unicode_escape(bytes, next + 2)?;
420 if !(0xdc00..=0xdfff).contains(&second) {
421 return Err(JsonError::InvalidEscape);
422 }
423 let high = u32::from(first - 0xd800);
424 let low = u32::from(second - 0xdc00);
425 (0x10000 + (high << 10) + low, next + 6)
426 } else if (0xdc00..=0xdfff).contains(&first) {
427 return Err(JsonError::InvalidEscape);
428 } else {
429 (u32::from(first), next)
430 };
431 let character = char::from_u32(scalar.0).ok_or(JsonError::InvalidEscape)?;
432 Ok((character, scalar.1))
433 }
434 _ => Err(JsonError::InvalidEscape),
435 }
436}
437
438fn unicode_escape(bytes: &[u8], start: usize) -> Result<u16, JsonError> {
439 let digits = bytes
440 .get(start..start + 4)
441 .ok_or(JsonError::InvalidEscape)?;
442 let mut value = 0u16;
443 for digit in digits {
444 value = value
445 .checked_mul(16)
446 .and_then(|value| hex(*digit).map(|digit| value + u16::from(digit)))
447 .ok_or(JsonError::InvalidEscape)?;
448 }
449 Ok(value)
450}
451
452fn hex(byte: u8) -> Option<u8> {
453 match byte {
454 b'0'..=b'9' => Some(byte - b'0'),
455 b'a'..=b'f' => Some(byte - b'a' + 10),
456 b'A'..=b'F' => Some(byte - b'A' + 10),
457 _ => None,
458 }
459}
460
461fn parse_number(bytes: &[u8], mut position: usize) -> Result<usize, JsonError> {
462 if bytes.get(position) == Some(&b'-') {
463 position += 1;
464 }
465 match bytes.get(position) {
466 Some(b'0') => position += 1,
467 Some(b'1'..=b'9') => {
468 position += 1;
469 while matches!(bytes.get(position), Some(b'0'..=b'9')) {
470 position += 1;
471 }
472 }
473 _ => return Err(JsonError::InvalidNumber),
474 }
475 if bytes.get(position) == Some(&b'.') {
476 position += 1;
477 let start = position;
478 while matches!(bytes.get(position), Some(b'0'..=b'9')) {
479 position += 1;
480 }
481 if position == start {
482 return Err(JsonError::InvalidNumber);
483 }
484 }
485 if matches!(bytes.get(position), Some(b'e' | b'E')) {
486 position += 1;
487 if matches!(bytes.get(position), Some(b'+' | b'-')) {
488 position += 1;
489 }
490 let start = position;
491 while matches!(bytes.get(position), Some(b'0'..=b'9')) {
492 position += 1;
493 }
494 if position == start {
495 return Err(JsonError::InvalidNumber);
496 }
497 }
498 Ok(position)
499}
500
501fn literal(bytes: &[u8], position: usize, literal: &[u8]) -> Result<usize, JsonError> {
502 if bytes.get(position..position + literal.len()) == Some(literal) {
503 Ok(position + literal.len())
504 } else {
505 Err(JsonError::InvalidSyntax)
506 }
507}
508
509fn whitespace(bytes: &[u8], mut position: usize) -> usize {
510 while matches!(bytes.get(position), Some(b' ' | b'\n' | b'\r' | b'\t')) {
511 position += 1;
512 }
513 position
514}
515
516fn copy_decoded(buffer: &mut [u8], output: &mut usize, bytes: &[u8]) -> Result<(), JsonError> {
517 let end = output
518 .checked_add(bytes.len())
519 .ok_or(JsonError::BufferTooSmall)?;
520 let destination = buffer
521 .get_mut(*output..end)
522 .ok_or(JsonError::BufferTooSmall)?;
523 destination.copy_from_slice(bytes);
524 *output = end;
525 Ok(())
526}
527
528#[cfg(test)]
529mod tests {
530 use super::{JsonError, Value};
531
532 #[test]
533 fn validates_and_iterates_nested_json() {
534 let value = Value::parse_document(br#" {"a":[1,{"b":true}],"skip":null} "#).unwrap();
535 let object = value.object().unwrap();
536 let array = object.required("a").unwrap().array().unwrap();
537 assert_eq!(array.iter().count(), 2);
538 assert!(object.get("missing").unwrap().is_none());
539 }
540
541 #[test]
542 fn decodes_strings_and_rejects_bad_surrogates() {
543 let value = Value::parse_document(br#""hello\n\u263a\ud83d\ude00""#).unwrap();
544 let string = value.string().unwrap();
545 let mut output = [0; 32];
546 assert_eq!(string.decode_into(&mut output).unwrap(), "hello\n☺😀");
547 assert_eq!(
548 Value::parse_document(br#""\ud83d!""#),
549 Err(JsonError::InvalidEscape)
550 );
551 }
552
553 #[test]
554 fn rejects_trailing_and_duplicate_requested_fields() {
555 assert!(Value::parse_document(b"{} x").is_err());
556 let object = Value::parse_document(br#"{"a":1,"\u0061":2}"#)
557 .unwrap()
558 .object()
559 .unwrap();
560 assert_eq!(object.get("a"), Err(JsonError::DuplicateField("a")));
561 }
562}