Skip to main content

amiss_wire/
json.rs

1use std::cmp::Ordering;
2use std::fmt;
3
4pub const MAX_SAFE_INTEGER: i64 = 9_007_199_254_740_991;
5const MAX_DEPTH: usize = 512;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub enum Value {
9    Null,
10    Bool(bool),
11    Integer(i64),
12    String(String),
13    Array(Vec<Value>),
14    /// Keys sorted by UTF-16 code units and unique; `parse` enforces both.
15    Object(Vec<(String, Value)>),
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum ErrorKind {
20    InvalidUtf8,
21    ByteOrderMark,
22    UnexpectedEnd,
23    UnexpectedByte,
24    TrailingContent,
25    DepthLimit,
26    DuplicateKey,
27    ControlCharacter,
28    InvalidEscape,
29    LoneSurrogate,
30    NegativeZero,
31    FractionOrExponent,
32    IntegerOutOfRange,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct Error {
37    pub kind: ErrorKind,
38    pub offset: usize,
39}
40
41/// Parses exactly one strict JSON value from the complete input.
42///
43/// # Errors
44///
45/// Returns the first defect with its byte offset. Beyond plain syntax
46/// errors, the restricted profile rejects a leading BOM, invalid UTF-8,
47/// duplicate object keys, lone surrogate escapes, raw control characters,
48/// `-0`, fractions and exponents, integers outside `MAX_SAFE_INTEGER`,
49/// nesting past the depth limit, and trailing content.
50pub fn parse(bytes: &[u8]) -> Result<Value, Error> {
51    if bytes.get(..3) == Some(&[0xEF, 0xBB, 0xBF]) {
52        return Err(Error {
53            kind: ErrorKind::ByteOrderMark,
54            offset: 0,
55        });
56    }
57    let text = std::str::from_utf8(bytes).map_err(|invalid| Error {
58        kind: ErrorKind::InvalidUtf8,
59        offset: invalid.valid_up_to(),
60    })?;
61    let mut parser = Parser {
62        bytes,
63        text,
64        pos: 0,
65    };
66    parser.skip_whitespace();
67    let value = parser.value(0)?;
68    parser.skip_whitespace();
69    if parser.pos == bytes.len() {
70        Ok(value)
71    } else {
72        Err(parser.error(ErrorKind::TrailingContent))
73    }
74}
75
76#[must_use]
77pub fn canonical(value: &Value) -> Vec<u8> {
78    let mut out = String::new();
79    stream(value, &mut out);
80    out.into_bytes()
81}
82
83/// The exact byte length `canonical` would produce, without materializing
84/// it: the counting canonical-serialization pass.
85#[must_use]
86pub fn canonical_length(value: &Value) -> u64 {
87    let mut count = ByteCount(0);
88    stream(value, &mut count);
89    count.0
90}
91
92/// A canonicalization output: receives the serialization in pieces, in
93/// order. Concatenating every piece yields exactly the `canonical` bytes.
94pub trait Sink {
95    fn write(&mut self, piece: &str);
96}
97
98impl Sink for String {
99    fn write(&mut self, piece: &str) {
100        self.push_str(piece);
101    }
102}
103
104/// A counting sink: the total byte length of every piece written.
105pub struct ByteCount(pub u64);
106
107impl Sink for ByteCount {
108    fn write(&mut self, piece: &str) {
109        self.0 = self
110            .0
111            .saturating_add(u64::try_from(piece.len()).unwrap_or(u64::MAX));
112    }
113}
114
115/// Streams the canonical serialization into the sink using its own
116/// transient scratch. For the fixed-scratch fatal lane use
117/// [`Scratch::stream`] with a reused scratch instead.
118pub fn stream<S: Sink + ?Sized>(value: &Value, sink: &mut S) {
119    let mut scratch = Scratch::new();
120    scratch.stream(value, sink);
121}
122
123/// The serializer's entire working memory: one member-order buffer per
124/// nesting level, reused across every sibling at that level, and one
125/// integer-format buffer. Streaming allocates nothing else, so a reserved
126/// `Scratch` makes serialization scratch a fixed space.
127pub struct Scratch {
128    order: Vec<Vec<usize>>,
129    number: String,
130}
131
132impl Scratch {
133    #[must_use]
134    pub fn new() -> Self {
135        Self {
136            order: Vec::new(),
137            number: String::with_capacity(24),
138        }
139    }
140
141    pub fn stream<S: Sink + ?Sized>(&mut self, value: &Value, sink: &mut S) {
142        self.write_value(value, sink, 0);
143    }
144
145    fn write_value<S: Sink + ?Sized>(&mut self, value: &Value, sink: &mut S, depth: usize) {
146        match value {
147            Value::Null => sink.write("null"),
148            Value::Bool(true) => sink.write("true"),
149            Value::Bool(false) => sink.write("false"),
150            Value::Integer(n) => {
151                self.number.clear();
152                let _infallible = fmt::Write::write_fmt(&mut self.number, format_args!("{n}"));
153                sink.write(&self.number);
154            }
155            Value::String(s) => write_string(sink, s),
156            Value::Array(items) => {
157                sink.write("[");
158                for (i, item) in items.iter().enumerate() {
159                    if i > 0 {
160                        sink.write(",");
161                    }
162                    self.write_value(item, sink, depth.saturating_add(1));
163                }
164                sink.write("]");
165            }
166            Value::Object(members) => {
167                self.order_members(members, depth);
168                sink.write("{");
169                let mut position = 0_usize;
170                loop {
171                    let member = self
172                        .order
173                        .get(depth)
174                        .and_then(|level| level.get(position))
175                        .and_then(|&index| members.get(index));
176                    let Some((key, value)) = member else { break };
177                    if position > 0 {
178                        sink.write(",");
179                    }
180                    write_string(sink, key);
181                    sink.write(":");
182                    self.write_value(value, sink, depth.saturating_add(1));
183                    position = position.saturating_add(1);
184                }
185                sink.write("}");
186            }
187        }
188    }
189
190    fn order_members(&mut self, members: &[(String, Value)], depth: usize) {
191        while self.order.len() <= depth {
192            self.order.push(Vec::new());
193        }
194        let Some(level) = self.order.get_mut(depth) else {
195            return;
196        };
197        level.clear();
198        level.extend(0..members.len());
199        level.sort_by(|&a, &b| {
200            let left = members.get(a).map_or("", |(key, _)| key.as_str());
201            let right = members.get(b).map_or("", |(key, _)| key.as_str());
202            utf16_cmp(left, right)
203        });
204    }
205}
206
207impl Default for Scratch {
208    fn default() -> Self {
209        Self::new()
210    }
211}
212
213fn utf16_cmp(a: &str, b: &str) -> Ordering {
214    a.encode_utf16().cmp(b.encode_utf16())
215}
216
217fn write_string<S: Sink + ?Sized>(sink: &mut S, s: &str) {
218    sink.write("\"");
219    let mut plain = 0_usize;
220    for (index, c) in s.char_indices() {
221        let escape: Option<&str> = match c {
222            '"' => Some("\\\""),
223            '\\' => Some("\\\\"),
224            '\u{8}' => Some("\\b"),
225            '\t' => Some("\\t"),
226            '\n' => Some("\\n"),
227            '\u{c}' => Some("\\f"),
228            '\r' => Some("\\r"),
229            c if u32::from(c) < 0x20 => Some(control_escape(c)),
230            _ => None,
231        };
232        if let Some(text) = escape {
233            if let Some(run) = s.get(plain..index) {
234                sink.write(run);
235            }
236            sink.write(text);
237            plain = index.saturating_add(c.len_utf8());
238        }
239    }
240    if let Some(run) = s.get(plain..) {
241        sink.write(run);
242    }
243    sink.write("\"");
244}
245
246/// The `\u00xx` form for the raw control characters without a short escape,
247/// as a static piece so streaming stays allocation-free.
248fn control_escape(c: char) -> &'static str {
249    const FORMS: [&str; 32] = [
250        "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
251        "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011",
252        "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019",
253        "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f",
254    ];
255    FORMS
256        .get(usize::try_from(u32::from(c)).unwrap_or(0))
257        .copied()
258        .unwrap_or("\\u0000")
259}
260
261struct Parser<'a> {
262    bytes: &'a [u8],
263    text: &'a str,
264    pos: usize,
265}
266
267impl Parser<'_> {
268    fn error(&self, kind: ErrorKind) -> Error {
269        Error {
270            kind,
271            offset: self.pos,
272        }
273    }
274
275    fn end_or_unexpected(&self) -> Error {
276        if self.peek().is_none() {
277            self.error(ErrorKind::UnexpectedEnd)
278        } else {
279            self.error(ErrorKind::UnexpectedByte)
280        }
281    }
282
283    fn peek(&self) -> Option<u8> {
284        self.bytes.get(self.pos).copied()
285    }
286
287    fn advance(&mut self) {
288        self.pos = self.pos.saturating_add(1);
289    }
290
291    fn skip_whitespace(&mut self) {
292        while matches!(self.peek(), Some(b' ' | b'\t' | b'\n' | b'\r')) {
293            self.advance();
294        }
295    }
296
297    fn expect(&mut self, byte: u8) -> Result<(), Error> {
298        if self.peek() == Some(byte) {
299            self.advance();
300            Ok(())
301        } else {
302            Err(self.end_or_unexpected())
303        }
304    }
305
306    fn literal(&mut self, text: &[u8]) -> Result<(), Error> {
307        for &byte in text {
308            self.expect(byte)?;
309        }
310        Ok(())
311    }
312
313    fn deeper(&self, depth: usize) -> Result<usize, Error> {
314        let next = depth.saturating_add(1);
315        if next > MAX_DEPTH {
316            Err(self.error(ErrorKind::DepthLimit))
317        } else {
318            Ok(next)
319        }
320    }
321
322    fn value(&mut self, depth: usize) -> Result<Value, Error> {
323        match self.peek() {
324            None => Err(self.error(ErrorKind::UnexpectedEnd)),
325            Some(b'n') => self.literal(b"null").map(|()| Value::Null),
326            Some(b't') => self.literal(b"true").map(|()| Value::Bool(true)),
327            Some(b'f') => self.literal(b"false").map(|()| Value::Bool(false)),
328            Some(b'"') => self.string().map(Value::String),
329            Some(b'{') => self.object(depth),
330            Some(b'[') => self.array(depth),
331            Some(b'-' | b'0'..=b'9') => self.number(),
332            Some(_) => Err(self.error(ErrorKind::UnexpectedByte)),
333        }
334    }
335
336    fn array(&mut self, depth: usize) -> Result<Value, Error> {
337        let depth = self.deeper(depth)?;
338        self.expect(b'[')?;
339        self.skip_whitespace();
340        let mut items = Vec::new();
341        if self.peek() == Some(b']') {
342            self.advance();
343            return Ok(Value::Array(items));
344        }
345        loop {
346            self.skip_whitespace();
347            items.push(self.value(depth)?);
348            self.skip_whitespace();
349            match self.peek() {
350                Some(b',') => self.advance(),
351                Some(b']') => {
352                    self.advance();
353                    return Ok(Value::Array(items));
354                }
355                _ => return Err(self.end_or_unexpected()),
356            }
357        }
358    }
359
360    fn object(&mut self, depth: usize) -> Result<Value, Error> {
361        let depth = self.deeper(depth)?;
362        self.expect(b'{')?;
363        self.skip_whitespace();
364        if self.peek() == Some(b'}') {
365            self.advance();
366            return Ok(Value::Object(Vec::new()));
367        }
368        let mut members: Vec<(String, Value, usize)> = Vec::new();
369        loop {
370            self.skip_whitespace();
371            let key_offset = self.pos;
372            if self.peek() != Some(b'"') {
373                return Err(self.end_or_unexpected());
374            }
375            let key = self.string()?;
376            self.skip_whitespace();
377            self.expect(b':')?;
378            self.skip_whitespace();
379            let value = self.value(depth)?;
380            members.push((key, value, key_offset));
381            self.skip_whitespace();
382            match self.peek() {
383                Some(b',') => self.advance(),
384                Some(b'}') => {
385                    self.advance();
386                    break;
387                }
388                _ => return Err(self.end_or_unexpected()),
389            }
390        }
391        members.sort_by(|a, b| utf16_cmp(&a.0, &b.0));
392        for pair in members.windows(2) {
393            if let [left, right] = pair
394                && left.0 == right.0
395            {
396                return Err(Error {
397                    kind: ErrorKind::DuplicateKey,
398                    offset: right.2,
399                });
400            }
401        }
402        Ok(Value::Object(
403            members.into_iter().map(|(k, v, _)| (k, v)).collect(),
404        ))
405    }
406
407    fn string(&mut self) -> Result<String, Error> {
408        self.expect(b'"')?;
409        let mut out = String::new();
410        let mut segment_start = self.pos;
411        loop {
412            match self.peek() {
413                None => return Err(self.error(ErrorKind::UnexpectedEnd)),
414                Some(b'"') => {
415                    self.flush(segment_start, &mut out)?;
416                    self.advance();
417                    return Ok(out);
418                }
419                Some(b'\\') => {
420                    self.flush(segment_start, &mut out)?;
421                    self.advance();
422                    self.escape(&mut out)?;
423                    segment_start = self.pos;
424                }
425                Some(byte) if byte < 0x20 => return Err(self.error(ErrorKind::ControlCharacter)),
426                Some(_) => self.advance(),
427            }
428        }
429    }
430
431    fn flush(&self, from: usize, out: &mut String) -> Result<(), Error> {
432        let segment = self
433            .text
434            .get(from..self.pos)
435            .ok_or_else(|| self.error(ErrorKind::InvalidUtf8))?;
436        out.push_str(segment);
437        Ok(())
438    }
439
440    fn escape(&mut self, out: &mut String) -> Result<(), Error> {
441        let byte = self
442            .peek()
443            .ok_or_else(|| self.error(ErrorKind::UnexpectedEnd))?;
444        self.advance();
445        let simple = match byte {
446            b'"' => Some('"'),
447            b'\\' => Some('\\'),
448            b'/' => Some('/'),
449            b'b' => Some('\u{8}'),
450            b'f' => Some('\u{c}'),
451            b'n' => Some('\n'),
452            b'r' => Some('\r'),
453            b't' => Some('\t'),
454            b'u' => None,
455            _ => {
456                self.pos = self.pos.saturating_sub(1);
457                return Err(self.error(ErrorKind::InvalidEscape));
458            }
459        };
460        if let Some(c) = simple {
461            out.push(c);
462            return Ok(());
463        }
464        let unit = self.hex4()?;
465        let code = match unit {
466            0xD800..=0xDBFF => {
467                if self.peek() != Some(b'\\') {
468                    return Err(self.error(ErrorKind::LoneSurrogate));
469                }
470                self.advance();
471                if self.peek() != Some(b'u') {
472                    return Err(self.error(ErrorKind::LoneSurrogate));
473                }
474                self.advance();
475                let low = self.hex4()?;
476                if !(0xDC00..=0xDFFF).contains(&low) {
477                    return Err(self.error(ErrorKind::LoneSurrogate));
478                }
479                combine_surrogates(unit, low)
480            }
481            0xDC00..=0xDFFF => return Err(self.error(ErrorKind::LoneSurrogate)),
482            unit => unit,
483        };
484        let c = char::from_u32(code).ok_or_else(|| self.error(ErrorKind::LoneSurrogate))?;
485        out.push(c);
486        Ok(())
487    }
488
489    fn hex4(&mut self) -> Result<u32, Error> {
490        let mut code = 0_u32;
491        for _ in 0_u8..4 {
492            let byte = self
493                .peek()
494                .ok_or_else(|| self.error(ErrorKind::UnexpectedEnd))?;
495            let digit = match byte {
496                b'0'..=b'9' => u32::from(byte.wrapping_sub(b'0')),
497                b'a'..=b'f' => u32::from(byte.wrapping_sub(b'a')).wrapping_add(10),
498                b'A'..=b'F' => u32::from(byte.wrapping_sub(b'A')).wrapping_add(10),
499                _ => return Err(self.error(ErrorKind::InvalidEscape)),
500            };
501            code = code.wrapping_shl(4) | digit;
502            self.advance();
503        }
504        Ok(code)
505    }
506
507    fn number(&mut self) -> Result<Value, Error> {
508        let negative = self.peek() == Some(b'-');
509        if negative {
510            self.advance();
511        }
512        let first = self
513            .peek()
514            .ok_or_else(|| self.error(ErrorKind::UnexpectedEnd))?;
515        let mut magnitude: i64 = match first {
516            b'0'..=b'9' => i64::from(first.wrapping_sub(b'0')),
517            _ => return Err(self.error(ErrorKind::UnexpectedByte)),
518        };
519        self.advance();
520        if magnitude == 0 {
521            if matches!(self.peek(), Some(b'0'..=b'9')) {
522                return Err(self.error(ErrorKind::UnexpectedByte));
523            }
524        } else {
525            while let Some(byte @ b'0'..=b'9') = self.peek() {
526                let digit = i64::from(byte.wrapping_sub(b'0'));
527                magnitude = magnitude
528                    .checked_mul(10)
529                    .and_then(|v| v.checked_add(digit))
530                    .ok_or_else(|| self.error(ErrorKind::IntegerOutOfRange))?;
531                self.advance();
532            }
533        }
534        if matches!(self.peek(), Some(b'.' | b'e' | b'E')) {
535            return Err(self.error(ErrorKind::FractionOrExponent));
536        }
537        if magnitude > MAX_SAFE_INTEGER {
538            return Err(self.error(ErrorKind::IntegerOutOfRange));
539        }
540        if negative {
541            if magnitude == 0 {
542                return Err(self.error(ErrorKind::NegativeZero));
543            }
544            magnitude = magnitude.wrapping_neg();
545        }
546        Ok(Value::Integer(magnitude))
547    }
548}
549
550#[expect(clippy::arithmetic_side_effects, reason = "operands are range-checked")]
551fn combine_surrogates(high: u32, low: u32) -> u32 {
552    0x10000 + ((high - 0xD800) << 10) + (low - 0xDC00)
553}