1use alloc::{
4 collections::BTreeSet,
5 format,
6 string::{String, ToString},
7 vec::Vec,
8};
9
10const SMALL_OBJECT: usize = 16;
13
14#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct Number(String);
17
18impl Number {
19 pub fn parse(text: &str) -> Option<Self> {
21 let mut p = Parser::new(text, Limits::default());
22 let number = p.number().ok()?;
23 (p.pos == text.len()).then_some(number)
24 }
25 pub fn as_str(&self) -> &str {
27 &self.0
28 }
29 pub fn as_i64(&self) -> Option<i64> {
31 let (negative, magnitude) = self.integer()?;
32 if negative {
33 if magnitude == 1u64 << 63 {
34 Some(i64::MIN)
35 } else {
36 i64::try_from(magnitude).ok().map(|v| -v)
37 }
38 } else {
39 i64::try_from(magnitude).ok()
40 }
41 }
42 pub fn as_u64(&self) -> Option<u64> {
44 let (negative, magnitude) = self.integer()?;
45 (!negative || magnitude == 0).then_some(magnitude)
46 }
47 fn integer(&self) -> Option<(bool, u64)> {
48 let negative = self.0.starts_with('-');
49 let text = self.0.strip_prefix('-').unwrap_or(&self.0);
50 let (mantissa, exponent) = if let Some(index) = text.find(['e', 'E']) {
51 let exponent = &text[index + 1..];
52 let exponent_negative = exponent.starts_with('-');
53 let mut magnitude = 0i32;
54 for byte in exponent.bytes().filter(|b| b.is_ascii_digit()) {
55 magnitude = (magnitude.saturating_mul(10) + (byte - b'0') as i32).min(1_000_000);
56 }
57 (
58 &text[..index],
59 if exponent_negative {
60 -magnitude
61 } else {
62 magnitude
63 },
64 )
65 } else {
66 (text, 0)
67 };
68 let fraction = mantissa
69 .find('.')
70 .map(|i| mantissa.len() - i - 1)
71 .unwrap_or(0) as i32;
72 let mut digits: Vec<u8> = mantissa
73 .bytes()
74 .filter(|b| *b != b'.')
75 .skip_while(|b| *b == b'0')
76 .collect();
77 if digits.is_empty() {
78 return Some((false, 0));
79 }
80 let mut scale = exponent - fraction;
81 while scale < 0 && digits.last() == Some(&b'0') {
82 digits.pop();
83 scale += 1;
84 }
85 if scale < 0 || scale > 20 || digits.len() + scale as usize > 20 {
86 return None;
87 }
88 let mut magnitude = 0u64;
89 for digit in digits {
90 magnitude = magnitude
91 .checked_mul(10)?
92 .checked_add((digit - b'0') as u64)?;
93 }
94 for _ in 0..scale {
95 magnitude = magnitude.checked_mul(10)?;
96 }
97 Some((negative, magnitude))
98 }
99}
100
101#[derive(Clone, Debug, PartialEq, Eq)]
103pub enum Value {
104 Null,
106 Bool(bool),
108 Number(Number),
110 String(String),
112 Array(Vec<Value>),
114 Object(Vec<(String, Value)>),
116}
117
118impl Value {
119 pub fn string(value: impl Into<String>) -> Self {
121 Self::String(value.into())
122 }
123 pub fn u64(value: u64) -> Self {
125 Self::Number(Number(value.to_string()))
126 }
127 pub fn i64(value: i64) -> Self {
129 Self::Number(Number(value.to_string()))
130 }
131 pub fn object<const N: usize>(fields: [(&str, Value); N]) -> Self {
133 let mut result = Self::Object(Vec::with_capacity(N));
134 for (key, value) in fields {
135 result.insert(key, value);
136 }
137 result
138 }
139 pub fn insert(&mut self, key: &str, value: Value) -> bool {
141 let Self::Object(fields) = self else {
142 return false;
143 };
144 if let Some((_, old)) = fields.iter_mut().find(|(name, _)| name == key) {
145 *old = value;
146 } else {
147 fields.push((key.into(), value));
148 }
149 true
150 }
151 pub fn get(&self, key: &str) -> Option<&Value> {
153 self.as_object()?
154 .iter()
155 .find(|(name, _)| name == key)
156 .map(|(_, value)| value)
157 }
158 pub fn as_object(&self) -> Option<&[(String, Value)]> {
160 match self {
161 Self::Object(value) => Some(value),
162 _ => None,
163 }
164 }
165 pub fn as_array(&self) -> Option<&[Value]> {
167 match self {
168 Self::Array(v) => Some(v),
169 _ => None,
170 }
171 }
172 pub fn as_str(&self) -> Option<&str> {
174 match self {
175 Self::String(v) => Some(v),
176 _ => None,
177 }
178 }
179 pub fn as_bool(&self) -> Option<bool> {
181 match self {
182 Self::Bool(v) => Some(*v),
183 _ => None,
184 }
185 }
186 pub fn as_u64(&self) -> Option<u64> {
188 match self {
189 Self::Number(v) => v.as_u64(),
190 _ => None,
191 }
192 }
193 pub fn as_i64(&self) -> Option<i64> {
195 match self {
196 Self::Number(v) => v.as_i64(),
197 _ => None,
198 }
199 }
200}
201
202#[derive(Clone, Copy, Debug)]
204pub struct Limits {
205 pub bytes: usize,
207 pub depth: usize,
209 pub values: usize,
211 pub string_bytes: usize,
213 pub members: usize,
215}
216
217impl Default for Limits {
218 fn default() -> Self {
219 Self {
220 bytes: 1_048_576,
221 depth: 32,
222 values: 16_384,
223 string_bytes: 262_144,
224 members: 4096,
225 }
226 }
227}
228
229#[derive(Clone, Debug, PartialEq, Eq)]
231pub struct Error {
232 pub offset: usize,
234 pub kind: &'static str,
236}
237
238pub fn parse(bytes: &[u8]) -> Result<Value, Error> {
240 parse_with_limits(bytes, Limits::default())
241}
242
243pub fn parse_with_limits(bytes: &[u8], limits: Limits) -> Result<Value, Error> {
245 if bytes.len() > limits.bytes {
246 return Err(Error {
247 offset: limits.bytes,
248 kind: "byte_limit",
249 });
250 }
251 let text = core::str::from_utf8(bytes).map_err(|e| Error {
252 offset: e.valid_up_to(),
253 kind: "invalid_utf8",
254 })?;
255 let mut parser = Parser::new(text, limits);
256 let value = parser.value(0)?;
257 parser.space();
258 if parser.pos != text.len() {
259 return parser.fail("trailing_data");
260 }
261 Ok(value)
262}
263
264struct Parser<'a> {
265 text: &'a str,
266 pos: usize,
267 values: usize,
268 limits: Limits,
269}
270
271impl<'a> Parser<'a> {
272 fn new(text: &'a str, limits: Limits) -> Self {
273 Self {
274 text,
275 pos: 0,
276 values: 0,
277 limits,
278 }
279 }
280 fn fail<T>(&self, kind: &'static str) -> Result<T, Error> {
281 Err(Error {
282 offset: self.pos,
283 kind,
284 })
285 }
286 fn peek(&self) -> Option<u8> {
287 self.text.as_bytes().get(self.pos).copied()
288 }
289 fn space(&mut self) {
290 while matches!(self.peek(), Some(b' ' | b'\r' | b'\n' | b'\t')) {
291 self.pos += 1;
292 }
293 }
294 fn take(&mut self, byte: u8) -> bool {
295 if self.peek() == Some(byte) {
296 self.pos += 1;
297 true
298 } else {
299 false
300 }
301 }
302 fn value(&mut self, depth: usize) -> Result<Value, Error> {
303 self.space();
304 if depth > self.limits.depth {
305 return self.fail("depth_limit");
306 }
307 self.values += 1;
308 if self.values > self.limits.values {
309 return self.fail("value_limit");
310 }
311 match self.peek() {
312 Some(b'n') => {
313 self.literal("null")?;
314 Ok(Value::Null)
315 }
316 Some(b't') => {
317 self.literal("true")?;
318 Ok(Value::Bool(true))
319 }
320 Some(b'f') => {
321 self.literal("false")?;
322 Ok(Value::Bool(false))
323 }
324 Some(b'"') => Ok(Value::String(self.string()?)),
325 Some(b'-' | b'0'..=b'9') => Ok(Value::Number(self.number()?)),
326 Some(b'[') => {
327 self.pos += 1;
328 self.space();
329 let mut values = Vec::new();
330 if self.take(b']') {
331 return Ok(Value::Array(values));
332 }
333 loop {
334 if values.len() >= self.limits.members {
335 return self.fail("member_limit");
336 }
337 values.push(self.value(depth + 1)?);
338 self.space();
339 if self.take(b']') {
340 break;
341 }
342 if !self.take(b',') {
343 return self.fail("expected_comma");
344 }
345 }
346 Ok(Value::Array(values))
347 }
348 Some(b'{') => {
349 self.pos += 1;
350 self.space();
351 let mut fields: Vec<(String, Value)> = Vec::new();
352 let mut names: Option<BTreeSet<String>> = None;
353 if self.take(b'}') {
354 return Ok(Value::Object(fields));
355 }
356 loop {
357 if fields.len() >= self.limits.members {
358 return self.fail("member_limit");
359 }
360 self.space();
361 let key = self.string()?;
362 self.space();
363 let duplicate = match &mut names {
364 Some(set) => !set.insert(key.clone()),
365 None => fields.iter().any(|(name, _)| name == &key),
366 };
367 if duplicate {
368 return self.fail("duplicate_key");
369 }
370 if names.is_none() && fields.len() >= SMALL_OBJECT {
371 names = Some(fields.iter().map(|(name, _)| name.clone()).chain([key.clone()]).collect());
372 }
373 if !self.take(b':') {
374 return self.fail("expected_colon");
375 }
376 fields.push((key, self.value(depth + 1)?));
377 self.space();
378 if self.take(b'}') {
379 break;
380 }
381 if !self.take(b',') {
382 return self.fail("expected_comma");
383 }
384 }
385 Ok(Value::Object(fields))
386 }
387 _ => self.fail("expected_value"),
388 }
389 }
390 fn literal(&mut self, text: &str) -> Result<(), Error> {
391 if self.text[self.pos..].starts_with(text) {
392 self.pos += text.len();
393 Ok(())
394 } else {
395 self.fail("invalid_literal")
396 }
397 }
398 fn number(&mut self) -> Result<Number, Error> {
399 let start = self.pos;
400 self.take(b'-');
401 if !self.take(b'0') {
402 if !matches!(self.peek(), Some(b'1'..=b'9')) {
403 return self.fail("invalid_number");
404 }
405 while matches!(self.peek(), Some(b'0'..=b'9')) {
406 self.pos += 1;
407 }
408 }
409 if self.take(b'.') {
410 let begin = self.pos;
411 while matches!(self.peek(), Some(b'0'..=b'9')) {
412 self.pos += 1;
413 }
414 if begin == self.pos {
415 return self.fail("invalid_number");
416 }
417 }
418 if self.take(b'e') || self.take(b'E') {
419 if !self.take(b'+') {
420 self.take(b'-');
421 }
422 let begin = self.pos;
423 while matches!(self.peek(), Some(b'0'..=b'9')) {
424 self.pos += 1;
425 }
426 if begin == self.pos {
427 return self.fail("invalid_number");
428 }
429 }
430 if self.pos - start > 256 {
431 return self.fail("number_limit");
432 }
433 Ok(Number(self.text[start..self.pos].into()))
434 }
435 fn hex4(&mut self) -> Result<u32, Error> {
436 let mut result = 0;
437 for _ in 0..4 {
438 let digit = match self.peek() {
439 Some(b'0'..=b'9') => self.peek().unwrap() - b'0',
440 Some(b'a'..=b'f') => self.peek().unwrap() - b'a' + 10,
441 Some(b'A'..=b'F') => self.peek().unwrap() - b'A' + 10,
442 _ => return self.fail("invalid_escape"),
443 };
444 self.pos += 1;
445 result = (result << 4) | digit as u32;
446 }
447 Ok(result)
448 }
449 fn string(&mut self) -> Result<String, Error> {
450 if !self.take(b'"') {
451 return self.fail("expected_string");
452 }
453 let mut result = String::new();
454 loop {
455 match self.peek() {
456 Some(b'"') => {
457 self.pos += 1;
458 return Ok(result);
459 }
460 Some(b'\\') => {
461 self.pos += 1;
462 let escaped = match self.peek() {
463 Some(b'"') => '"',
464 Some(b'\\') => '\\',
465 Some(b'/') => '/',
466 Some(b'b') => '\u{8}',
467 Some(b'f') => '\u{c}',
468 Some(b'n') => '\n',
469 Some(b'r') => '\r',
470 Some(b't') => '\t',
471 Some(b'u') => {
472 self.pos += 1;
473 let first = self.hex4()?;
474 let scalar = if (0xD800..=0xDBFF).contains(&first) {
475 if !self.take(b'\\') || !self.take(b'u') {
476 return self.fail("unpaired_surrogate");
477 }
478 let low = self.hex4()?;
479 if !(0xDC00..=0xDFFF).contains(&low) {
480 return self.fail("unpaired_surrogate");
481 }
482 0x10000 + ((first - 0xD800) << 10) + (low - 0xDC00)
483 } else {
484 first
485 };
486 let Some(ch) = char::from_u32(scalar) else {
487 return self.fail("unpaired_surrogate");
488 };
489 result.push(ch);
490 if result.len() > self.limits.string_bytes {
491 return self.fail("string_limit");
492 }
493 continue;
494 }
495 _ => return self.fail("invalid_escape"),
496 };
497 self.pos += 1;
498 result.push(escaped);
499 }
500 Some(0..=31) => return self.fail("unescaped_control"),
501 Some(_) => {
502 let Some(ch) = self.text[self.pos..].chars().next() else {
503 return self.fail("unterminated_string");
504 };
505 self.pos += ch.len_utf8();
506 result.push(ch);
507 }
508 None => return self.fail("unterminated_string"),
509 }
510 if result.len() > self.limits.string_bytes {
511 return self.fail("string_limit");
512 }
513 }
514 }
515}
516
517pub fn stringify(value: &Value) -> Result<String, Error> {
519 stringify_with_limits(value, Limits::default())
520}
521
522pub fn stringify_with_limits(value: &Value, limits: Limits) -> Result<String, Error> {
524 let mut writer = Writer {
525 out: String::new(),
526 limits,
527 values: 0,
528 indent: 0,
529 };
530 writer.value(value, 0)?;
531 Ok(writer.out)
532}
533
534pub fn stringify_pretty(value: &Value, limits: Limits, indent: usize) -> Result<String, Error> {
538 let mut writer = Writer {
539 out: String::new(),
540 limits,
541 values: 0,
542 indent: indent.clamp(1, 8),
543 };
544 writer.value(value, 0)?;
545 Ok(writer.out)
546}
547
548struct Writer {
549 out: String,
550 limits: Limits,
551 values: usize,
552 indent: usize,
554}
555
556impl Writer {
557 fn fail<T>(&self, kind: &'static str) -> Result<T, Error> {
558 Err(Error {
559 offset: self.out.len(),
560 kind,
561 })
562 }
563 fn push(&mut self, text: &str) -> Result<(), Error> {
564 if text.len() > self.limits.bytes.saturating_sub(self.out.len()) {
565 return self.fail("byte_limit");
566 }
567 self.out.push_str(text);
568 Ok(())
569 }
570 fn newline(&mut self, depth: usize) -> Result<(), Error> {
572 if self.indent == 0 {
573 return Ok(());
574 }
575 let n = 1 + depth * self.indent;
576 if n > self.limits.bytes.saturating_sub(self.out.len()) {
577 return self.fail("byte_limit");
578 }
579 self.out.push('\n');
580 for _ in 1..n {
581 self.out.push(' ');
582 }
583 Ok(())
584 }
585 fn string(&mut self, text: &str) -> Result<(), Error> {
586 if text.len() > self.limits.string_bytes {
587 return self.fail("string_limit");
588 }
589 self.push("\"")?;
590 for ch in text.chars() {
591 match ch {
592 '"' => self.push("\\\"")?,
593 '\\' => self.push("\\\\")?,
594 '\n' => self.push("\\n")?,
595 '\r' => self.push("\\r")?,
596 '\t' => self.push("\\t")?,
597 ch if (ch as u32) < 32 => self.push(&format!("\\u{:04x}", ch as u32))?,
598 ch => {
599 let mut bytes = [0; 4];
600 self.push(ch.encode_utf8(&mut bytes))?;
601 }
602 }
603 }
604 self.push("\"")
605 }
606 fn value(&mut self, value: &Value, depth: usize) -> Result<(), Error> {
607 if depth > self.limits.depth {
608 return self.fail("depth_limit");
609 }
610 self.values += 1;
611 if self.values > self.limits.values {
612 return self.fail("value_limit");
613 }
614 match value {
615 Value::Null => self.push("null"),
616 Value::Bool(v) => self.push(if *v { "true" } else { "false" }),
617 Value::Number(v) => self.push(v.as_str()),
618 Value::String(v) => self.string(v),
619 Value::Array(values) => {
620 if values.len() > self.limits.members {
621 return self.fail("member_limit");
622 }
623 self.push("[")?;
624 for (i, item) in values.iter().enumerate() {
625 if i != 0 {
626 self.push(",")?;
627 }
628 self.newline(depth + 1)?;
629 self.value(item, depth + 1)?;
630 }
631 if !values.is_empty() {
632 self.newline(depth)?;
633 }
634 self.push("]")
635 }
636 Value::Object(fields) => {
637 if fields.len() > self.limits.members {
638 return self.fail("member_limit");
639 }
640 self.push("{")?;
641 let mut names: BTreeSet<&str> = BTreeSet::new();
642 for (i, (name, item)) in fields.iter().enumerate() {
643 let duplicate = if fields.len() > SMALL_OBJECT {
644 !names.insert(name)
645 } else {
646 fields[..i].iter().any(|(key, _)| key == name)
647 };
648 if duplicate {
649 return self.fail("duplicate_key");
650 }
651 if i != 0 {
652 self.push(",")?;
653 }
654 self.newline(depth + 1)?;
655 self.string(name)?;
656 self.push(if self.indent > 0 { ": " } else { ":" })?;
657 self.value(item, depth + 1)?;
658 }
659 if !fields.is_empty() {
660 self.newline(depth)?;
661 }
662 self.push("}")
663 }
664 }
665 }
666}