Skip to main content

tilewright_jsonc/
lib.rs

1// Copyright 2026 Seraphina Studios
2// SPDX-License-Identifier: MIT
3
4//! Strict, lossless, bounded JSONC for Tilewright world sources.
5//!
6//! The dialect is UTF-8 JSON (RFC 8259) plus `//` and `/* */` comments, as
7//! specified in `docs/spec/FORMAT.md` section 3. Trailing commas, duplicate
8//! keys, byte-order marks, non-finite numbers and out-of-range integers are
9//! errors. Every limit is enforced while reading.
10//!
11//! A [`Document`] keeps its source text unchanged. Every [`Value`] records the
12//! byte [`Span`] it occupies, so tools can replace exactly one value and keep
13//! comments, ordering and whitespace byte for byte.
14//!
15//! ```
16//! use tilewright_jsonc::{Document, Limits};
17//!
18//! let source = "{\n  // terrain\n  \"fill\": 0\n}\n";
19//! let document = Document::parse(source, &Limits::default()).unwrap();
20//! let fill = document.root().get("fill").unwrap();
21//! assert_eq!(fill.as_i64(), Some(0));
22//! let edited = document.replace(fill.span(), "4", &Limits::default()).unwrap();
23//! assert_eq!(edited.source(), "{\n  // terrain\n  \"fill\": 4\n}\n");
24//! ```
25
26use std::{collections::HashSet, fmt};
27
28/// Largest integer magnitude accepted, `2^53 - 1`.
29pub const MAX_SAFE_INTEGER: i64 = 9_007_199_254_740_991;
30
31/// Parser limits. [`Limits::default`] is the format's fixed contract.
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct Limits {
34    pub max_input_bytes: usize,
35    pub max_depth: usize,
36    pub max_values: usize,
37    pub max_array_items: usize,
38    pub max_object_keys: usize,
39    pub max_string_bytes: usize,
40    pub max_number_bytes: usize,
41    pub max_comments: usize,
42    pub max_comment_bytes: usize,
43    pub max_lines: usize,
44    pub max_line_bytes: usize,
45}
46
47impl Default for Limits {
48    fn default() -> Self {
49        Self {
50            max_input_bytes: 64 * 1024 * 1024,
51            max_depth: 64,
52            max_values: 1_000_000,
53            max_array_items: 250_000,
54            max_object_keys: 256,
55            max_string_bytes: 1024 * 1024,
56            max_number_bytes: 128,
57            max_comments: 100_000,
58            max_comment_bytes: 4 * 1024 * 1024,
59            max_lines: 250_000,
60            max_line_bytes: 1024 * 1024,
61        }
62    }
63}
64
65/// A half-open byte range `[start, end)` in the document source.
66#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
67pub struct Span {
68    pub start: usize,
69    pub end: usize,
70}
71
72impl Span {
73    #[must_use]
74    pub const fn len(self) -> usize {
75        self.end - self.start
76    }
77
78    #[must_use]
79    pub const fn is_empty(self) -> bool {
80        self.start == self.end
81    }
82}
83
84/// A parsed value with its exact source span.
85#[derive(Clone, Debug, PartialEq)]
86pub enum Value {
87    Null { span: Span },
88    Bool { value: bool, span: Span },
89    Integer { value: i64, span: Span },
90    Float { value: f64, span: Span },
91    String { value: String, span: Span },
92    Array { items: Vec<Value>, span: Span },
93    Object { members: Vec<Member>, span: Span },
94}
95
96/// One object member. Members keep their source order.
97#[derive(Clone, Debug, PartialEq)]
98pub struct Member {
99    pub key: String,
100    pub key_span: Span,
101    pub value: Value,
102}
103
104/// A step in a [`Value::pointer`] path.
105#[derive(Clone, Copy, Debug, Eq, PartialEq)]
106pub enum Segment<'a> {
107    Key(&'a str),
108    Index(usize),
109}
110
111impl Value {
112    #[must_use]
113    pub const fn span(&self) -> Span {
114        match self {
115            Self::Null { span }
116            | Self::Bool { span, .. }
117            | Self::Integer { span, .. }
118            | Self::Float { span, .. }
119            | Self::String { span, .. }
120            | Self::Array { span, .. }
121            | Self::Object { span, .. } => *span,
122        }
123    }
124
125    /// A short name for diagnostics: `null`, `boolean`, `integer`, `number`,
126    /// `string`, `array` or `object`.
127    #[must_use]
128    pub const fn kind(&self) -> &'static str {
129        match self {
130            Self::Null { .. } => "null",
131            Self::Bool { .. } => "boolean",
132            Self::Integer { .. } => "integer",
133            Self::Float { .. } => "number",
134            Self::String { .. } => "string",
135            Self::Array { .. } => "array",
136            Self::Object { .. } => "object",
137        }
138    }
139
140    #[must_use]
141    pub const fn as_bool(&self) -> Option<bool> {
142        match self {
143            Self::Bool { value, .. } => Some(*value),
144            _ => None,
145        }
146    }
147
148    #[must_use]
149    pub const fn as_i64(&self) -> Option<i64> {
150        match self {
151            Self::Integer { value, .. } => Some(*value),
152            _ => None,
153        }
154    }
155
156    /// The numeric value of an integer or float.
157    #[must_use]
158    #[allow(clippy::cast_precision_loss)]
159    pub const fn as_f64(&self) -> Option<f64> {
160        match self {
161            Self::Integer { value, .. } => Some(*value as f64),
162            Self::Float { value, .. } => Some(*value),
163            _ => None,
164        }
165    }
166
167    #[must_use]
168    pub fn as_str(&self) -> Option<&str> {
169        match self {
170            Self::String { value, .. } => Some(value),
171            _ => None,
172        }
173    }
174
175    #[must_use]
176    pub fn as_array(&self) -> Option<&[Value]> {
177        match self {
178            Self::Array { items, .. } => Some(items),
179            _ => None,
180        }
181    }
182
183    #[must_use]
184    pub fn as_object(&self) -> Option<&[Member]> {
185        match self {
186            Self::Object { members, .. } => Some(members),
187            _ => None,
188        }
189    }
190
191    /// The value of an object member, if this is an object that has it.
192    #[must_use]
193    pub fn get(&self, key: &str) -> Option<&Value> {
194        self.as_object()?
195            .iter()
196            .find(|member| member.key == key)
197            .map(|member| &member.value)
198    }
199
200    /// The object member itself, including its key span.
201    #[must_use]
202    pub fn member(&self, key: &str) -> Option<&Member> {
203        self.as_object()?.iter().find(|member| member.key == key)
204    }
205
206    /// Follows a path of keys and indexes.
207    #[must_use]
208    pub fn pointer(&self, path: &[Segment<'_>]) -> Option<&Value> {
209        path.iter().try_fold(self, |value, segment| match segment {
210            Segment::Key(key) => value.get(key),
211            Segment::Index(index) => value.as_array()?.get(*index),
212        })
213    }
214}
215
216/// A parsed document that owns its unchanged source text.
217#[derive(Clone, Debug, PartialEq)]
218pub struct Document {
219    source: String,
220    root: Value,
221}
222
223impl Document {
224    /// Parses a complete document.
225    ///
226    /// # Errors
227    /// Returns the first syntax or limit violation with its byte offset.
228    pub fn parse(source: impl Into<String>, limits: &Limits) -> Result<Self, Error> {
229        let source = source.into();
230        let root = parse_value_tree(&source, limits)?;
231        Ok(Self { source, root })
232    }
233
234    #[must_use]
235    pub fn source(&self) -> &str {
236        &self.source
237    }
238
239    #[must_use]
240    pub const fn root(&self) -> &Value {
241        &self.root
242    }
243
244    /// The exact source text of a span.
245    ///
246    /// # Panics
247    /// Panics if the span is not a span of this document.
248    #[must_use]
249    pub fn text(&self, span: Span) -> &str {
250        &self.source[span.start..span.end]
251    }
252
253    /// Canonical minified JSON for a value of this document: no comments or
254    /// whitespace, members in source order, numbers spelled exactly as in the
255    /// source, and strings escaped minimally (`"`, `\\` and control
256    /// characters only). Equal values from equal source text always give
257    /// equal output.
258    ///
259    /// # Panics
260    /// Panics if the value is not part of this document.
261    #[must_use]
262    pub fn canonical(&self, value: &Value) -> String {
263        let mut output = String::new();
264        self.write_canonical(value, &mut output);
265        output
266    }
267
268    fn write_canonical(&self, value: &Value, output: &mut String) {
269        match value {
270            Value::Null { .. } => output.push_str("null"),
271            Value::Bool { value, .. } => output.push_str(if *value { "true" } else { "false" }),
272            Value::Integer { span, .. } | Value::Float { span, .. } => {
273                output.push_str(self.text(*span));
274            }
275            Value::String { value, .. } => write_json_string(value, output),
276            Value::Array { items, .. } => {
277                output.push('[');
278                for (index, item) in items.iter().enumerate() {
279                    if index > 0 {
280                        output.push(',');
281                    }
282                    self.write_canonical(item, output);
283                }
284                output.push(']');
285            }
286            Value::Object { members, .. } => {
287                output.push('{');
288                for (index, member) in members.iter().enumerate() {
289                    if index > 0 {
290                        output.push(',');
291                    }
292                    write_json_string(&member.key, output);
293                    output.push(':');
294                    self.write_canonical(&member.value, output);
295                }
296                output.push('}');
297            }
298        }
299    }
300
301    /// Replaces one span with new text and parses the result. Every byte
302    /// outside the span is preserved.
303    ///
304    /// # Errors
305    /// Returns [`ErrorCode::InvalidEdit`] for a span outside the document or
306    /// not on character boundaries, or any error of the edited document.
307    pub fn replace(&self, span: Span, text: &str, limits: &Limits) -> Result<Self, Error> {
308        if span.start > span.end
309            || span.end > self.source.len()
310            || !self.source.is_char_boundary(span.start)
311            || !self.source.is_char_boundary(span.end)
312        {
313            return Err(Error {
314                code: ErrorCode::InvalidEdit,
315                offset: span.start.min(self.source.len()),
316                line: 0,
317                column: 0,
318            });
319        }
320        let mut edited = String::with_capacity(self.source.len() - span.len() + text.len());
321        edited.push_str(&self.source[..span.start]);
322        edited.push_str(text);
323        edited.push_str(&self.source[span.end..]);
324        Self::parse(edited, limits)
325    }
326}
327
328/// Stable error codes.
329#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
330pub enum ErrorCode {
331    InputTooLarge,
332    TooManyLines,
333    LineTooLong,
334    ByteOrderMark,
335    UnexpectedEnd,
336    UnexpectedCharacter,
337    ExpectedValue,
338    ExpectedKey,
339    ExpectedColon,
340    ExpectedCommaOrEnd,
341    TrailingComma,
342    TrailingContent,
343    DuplicateKey,
344    InvalidNumber,
345    NumberTooLong,
346    IntegerOutOfRange,
347    NonFiniteNumber,
348    UnterminatedString,
349    ControlCharacterInString,
350    InvalidEscape,
351    InvalidUnicodeEscape,
352    NulInString,
353    StringTooLong,
354    UnterminatedComment,
355    TooManyComments,
356    DepthLimit,
357    ValueLimit,
358    ArrayLimit,
359    ObjectLimit,
360    InvalidEdit,
361}
362
363impl ErrorCode {
364    /// The stable string form, for diagnostics and tests.
365    #[must_use]
366    pub const fn as_str(self) -> &'static str {
367        match self {
368            Self::InputTooLarge => "jsonc.input_too_large",
369            Self::TooManyLines => "jsonc.too_many_lines",
370            Self::LineTooLong => "jsonc.line_too_long",
371            Self::ByteOrderMark => "jsonc.byte_order_mark",
372            Self::UnexpectedEnd => "jsonc.unexpected_end",
373            Self::UnexpectedCharacter => "jsonc.unexpected_character",
374            Self::ExpectedValue => "jsonc.expected_value",
375            Self::ExpectedKey => "jsonc.expected_key",
376            Self::ExpectedColon => "jsonc.expected_colon",
377            Self::ExpectedCommaOrEnd => "jsonc.expected_comma_or_end",
378            Self::TrailingComma => "jsonc.trailing_comma",
379            Self::TrailingContent => "jsonc.trailing_content",
380            Self::DuplicateKey => "jsonc.duplicate_key",
381            Self::InvalidNumber => "jsonc.invalid_number",
382            Self::NumberTooLong => "jsonc.number_too_long",
383            Self::IntegerOutOfRange => "jsonc.integer_out_of_range",
384            Self::NonFiniteNumber => "jsonc.non_finite_number",
385            Self::UnterminatedString => "jsonc.unterminated_string",
386            Self::ControlCharacterInString => "jsonc.control_character_in_string",
387            Self::InvalidEscape => "jsonc.invalid_escape",
388            Self::InvalidUnicodeEscape => "jsonc.invalid_unicode_escape",
389            Self::NulInString => "jsonc.nul_in_string",
390            Self::StringTooLong => "jsonc.string_too_long",
391            Self::UnterminatedComment => "jsonc.unterminated_comment",
392            Self::TooManyComments => "jsonc.too_many_comments",
393            Self::DepthLimit => "jsonc.depth_limit",
394            Self::ValueLimit => "jsonc.value_limit",
395            Self::ArrayLimit => "jsonc.array_limit",
396            Self::ObjectLimit => "jsonc.object_limit",
397            Self::InvalidEdit => "jsonc.invalid_edit",
398        }
399    }
400}
401
402/// A parse error. `line` and `column` are 1-based (column counts characters);
403/// both are 0 when no position applies.
404#[derive(Clone, Copy, Debug, Eq, PartialEq)]
405pub struct Error {
406    pub code: ErrorCode,
407    pub offset: usize,
408    pub line: usize,
409    pub column: usize,
410}
411
412impl fmt::Display for Error {
413    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
414        if self.line == 0 {
415            write!(formatter, "{} at byte {}", self.code.as_str(), self.offset)
416        } else {
417            write!(
418                formatter,
419                "{} at line {}, column {}",
420                self.code.as_str(),
421                self.line,
422                self.column
423            )
424        }
425    }
426}
427
428impl std::error::Error for Error {}
429
430/// Appends `value` as a JSON string with minimal escaping.
431pub fn write_json_string(value: &str, output: &mut String) {
432    use std::fmt::Write as _;
433    output.push('"');
434    for character in value.chars() {
435        match character {
436            '"' => output.push_str("\\\""),
437            '\\' => output.push_str("\\\\"),
438            '\n' => output.push_str("\\n"),
439            '\r' => output.push_str("\\r"),
440            '\t' => output.push_str("\\t"),
441            '\u{8}' => output.push_str("\\b"),
442            '\u{c}' => output.push_str("\\f"),
443            control if u32::from(control) < 0x20 => {
444                let _ = write!(output, "\\u{:04x}", u32::from(control));
445            }
446            other => output.push(other),
447        }
448    }
449    output.push('"');
450}
451
452fn parse_value_tree(source: &str, limits: &Limits) -> Result<Value, Error> {
453    let error_at = |code, offset| Err(locate(source, code, offset));
454    if source.len() > limits.max_input_bytes {
455        return error_at(ErrorCode::InputTooLarge, 0);
456    }
457    if source.starts_with('\u{feff}') {
458        return error_at(ErrorCode::ByteOrderMark, 0);
459    }
460    let mut lines = 1_usize;
461    let mut line_start = 0_usize;
462    for (offset, byte) in source.bytes().enumerate() {
463        if byte == b'\n' {
464            if offset - line_start > limits.max_line_bytes {
465                return error_at(ErrorCode::LineTooLong, line_start);
466            }
467            lines += 1;
468            line_start = offset + 1;
469            if lines > limits.max_lines {
470                return error_at(ErrorCode::TooManyLines, offset);
471            }
472        }
473    }
474    if source.len() - line_start > limits.max_line_bytes {
475        return error_at(ErrorCode::LineTooLong, line_start);
476    }
477    let mut parser = Parser {
478        source,
479        bytes: source.as_bytes(),
480        position: 0,
481        limits,
482        values: 0,
483        comments: 0,
484        comment_bytes: 0,
485    };
486    parser
487        .document()
488        .map_err(|(code, offset)| locate(source, code, offset))
489}
490
491fn locate(source: &str, code: ErrorCode, offset: usize) -> Error {
492    let offset = offset.min(source.len());
493    let mut boundary = offset;
494    while !source.is_char_boundary(boundary) {
495        boundary -= 1;
496    }
497    let before = &source[..boundary];
498    let line = before.bytes().filter(|byte| *byte == b'\n').count() + 1;
499    let line_start = before.rfind('\n').map_or(0, |index| index + 1);
500    let column = source[line_start..boundary].chars().count() + 1;
501    Error {
502        code,
503        offset,
504        line,
505        column,
506    }
507}
508
509type Failure = (ErrorCode, usize);
510
511struct Parser<'a> {
512    source: &'a str,
513    bytes: &'a [u8],
514    position: usize,
515    limits: &'a Limits,
516    values: usize,
517    comments: usize,
518    comment_bytes: usize,
519}
520
521impl Parser<'_> {
522    fn document(&mut self) -> Result<Value, Failure> {
523        self.trivia()?;
524        if self.position == self.bytes.len() {
525            return Err((ErrorCode::ExpectedValue, self.position));
526        }
527        let root = self.value(0)?;
528        self.trivia()?;
529        if self.position != self.bytes.len() {
530            return Err((ErrorCode::TrailingContent, self.position));
531        }
532        Ok(root)
533    }
534
535    fn peek(&self) -> Option<u8> {
536        self.bytes.get(self.position).copied()
537    }
538
539    fn trivia(&mut self) -> Result<(), Failure> {
540        loop {
541            match self.peek() {
542                Some(b' ' | b'\t' | b'\n' | b'\r') => self.position += 1,
543                Some(b'/') => self.comment()?,
544                _ => return Ok(()),
545            }
546        }
547    }
548
549    fn comment(&mut self) -> Result<(), Failure> {
550        let start = self.position;
551        match self.bytes.get(start + 1) {
552            Some(b'/') => {
553                let end = self.bytes[start..]
554                    .iter()
555                    .position(|byte| *byte == b'\n')
556                    .map_or(self.bytes.len(), |index| start + index);
557                self.position = end;
558            }
559            Some(b'*') => {
560                let body = start + 2;
561                let close = self.source[body..]
562                    .find("*/")
563                    .ok_or((ErrorCode::UnterminatedComment, start))?;
564                self.position = body + close + 2;
565            }
566            _ => return Err((ErrorCode::UnexpectedCharacter, start)),
567        }
568        self.comments += 1;
569        self.comment_bytes += self.position - start;
570        if self.comments > self.limits.max_comments
571            || self.comment_bytes > self.limits.max_comment_bytes
572        {
573            return Err((ErrorCode::TooManyComments, start));
574        }
575        Ok(())
576    }
577
578    fn count_value(&mut self, offset: usize) -> Result<(), Failure> {
579        self.values += 1;
580        if self.values > self.limits.max_values {
581            return Err((ErrorCode::ValueLimit, offset));
582        }
583        Ok(())
584    }
585
586    fn value(&mut self, depth: usize) -> Result<Value, Failure> {
587        let start = self.position;
588        self.count_value(start)?;
589        match self.peek() {
590            None => Err((ErrorCode::UnexpectedEnd, start)),
591            Some(b'{') => self.object(depth + 1),
592            Some(b'[') => self.array(depth + 1),
593            Some(b'"') => {
594                let value = self.string()?;
595                Ok(Value::String {
596                    value,
597                    span: Span {
598                        start,
599                        end: self.position,
600                    },
601                })
602            }
603            Some(b't') => self.literal(
604                "true",
605                Value::Bool {
606                    value: true,
607                    span: Span {
608                        start,
609                        end: start + 4,
610                    },
611                },
612            ),
613            Some(b'f') => self.literal(
614                "false",
615                Value::Bool {
616                    value: false,
617                    span: Span {
618                        start,
619                        end: start + 5,
620                    },
621                },
622            ),
623            Some(b'n') => self.literal(
624                "null",
625                Value::Null {
626                    span: Span {
627                        start,
628                        end: start + 4,
629                    },
630                },
631            ),
632            Some(b'-' | b'0'..=b'9') => self.number(),
633            Some(_) => Err((ErrorCode::ExpectedValue, start)),
634        }
635    }
636
637    fn literal(&mut self, word: &str, value: Value) -> Result<Value, Failure> {
638        if self.bytes[self.position..].starts_with(word.as_bytes()) {
639            self.position += word.len();
640            Ok(value)
641        } else {
642            Err((ErrorCode::ExpectedValue, self.position))
643        }
644    }
645
646    fn number(&mut self) -> Result<Value, Failure> {
647        let start = self.position;
648        let mut cursor = start;
649        let digit = |byte: Option<&u8>| matches!(byte, Some(b'0'..=b'9'));
650        if self.bytes.get(cursor) == Some(&b'-') {
651            cursor += 1;
652        }
653        match self.bytes.get(cursor) {
654            Some(b'0') => cursor += 1,
655            Some(b'1'..=b'9') => {
656                while digit(self.bytes.get(cursor)) {
657                    cursor += 1;
658                }
659            }
660            _ => return Err((ErrorCode::InvalidNumber, start)),
661        }
662        let mut integer = true;
663        if self.bytes.get(cursor) == Some(&b'.') {
664            integer = false;
665            cursor += 1;
666            if !digit(self.bytes.get(cursor)) {
667                return Err((ErrorCode::InvalidNumber, start));
668            }
669            while digit(self.bytes.get(cursor)) {
670                cursor += 1;
671            }
672        }
673        if matches!(self.bytes.get(cursor), Some(b'e' | b'E')) {
674            integer = false;
675            cursor += 1;
676            if matches!(self.bytes.get(cursor), Some(b'+' | b'-')) {
677                cursor += 1;
678            }
679            if !digit(self.bytes.get(cursor)) {
680                return Err((ErrorCode::InvalidNumber, start));
681            }
682            while digit(self.bytes.get(cursor)) {
683                cursor += 1;
684            }
685        }
686        if matches!(
687            self.bytes.get(cursor),
688            Some(b'0'..=b'9' | b'.' | b'e' | b'E' | b'+' | b'-' | b'x' | b'X')
689        ) {
690            return Err((ErrorCode::InvalidNumber, start));
691        }
692        if cursor - start > self.limits.max_number_bytes {
693            return Err((ErrorCode::NumberTooLong, start));
694        }
695        let text = &self.source[start..cursor];
696        let span = Span { start, end: cursor };
697        self.position = cursor;
698        if integer {
699            let value = text
700                .parse::<i64>()
701                .map_err(|_| (ErrorCode::IntegerOutOfRange, start))?;
702            if !(-MAX_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&value) {
703                return Err((ErrorCode::IntegerOutOfRange, start));
704            }
705            Ok(Value::Integer { value, span })
706        } else {
707            let value = text
708                .parse::<f64>()
709                .map_err(|_| (ErrorCode::InvalidNumber, start))?;
710            if !value.is_finite() {
711                return Err((ErrorCode::NonFiniteNumber, start));
712            }
713            Ok(Value::Float { value, span })
714        }
715    }
716
717    fn string(&mut self) -> Result<String, Failure> {
718        let start = self.position;
719        self.position += 1;
720        let mut value = String::new();
721        loop {
722            let run_start = self.position;
723            while let Some(byte) = self.peek() {
724                if byte == b'"' || byte == b'\\' || byte < 0x20 {
725                    break;
726                }
727                self.position += 1;
728            }
729            value.push_str(&self.source[run_start..self.position]);
730            if value.len() > self.limits.max_string_bytes {
731                return Err((ErrorCode::StringTooLong, start));
732            }
733            match self.peek() {
734                None => return Err((ErrorCode::UnterminatedString, start)),
735                Some(b'"') => {
736                    self.position += 1;
737                    return Ok(value);
738                }
739                Some(b'\\') => {
740                    let escaped = self.escape()?;
741                    if escaped == '\0' {
742                        return Err((ErrorCode::NulInString, self.position));
743                    }
744                    value.push(escaped);
745                    if value.len() > self.limits.max_string_bytes {
746                        return Err((ErrorCode::StringTooLong, start));
747                    }
748                }
749                Some(_) => return Err((ErrorCode::ControlCharacterInString, self.position)),
750            }
751        }
752    }
753
754    fn escape(&mut self) -> Result<char, Failure> {
755        let start = self.position;
756        let kind = self
757            .bytes
758            .get(start + 1)
759            .copied()
760            .ok_or((ErrorCode::UnterminatedString, start))?;
761        self.position += 2;
762        Ok(match kind {
763            b'"' => '"',
764            b'\\' => '\\',
765            b'/' => '/',
766            b'b' => '\u{8}',
767            b'f' => '\u{c}',
768            b'n' => '\n',
769            b'r' => '\r',
770            b't' => '\t',
771            b'u' => {
772                let first = self.hex4(start)?;
773                match first {
774                    0xd800..=0xdbff => {
775                        if self.bytes.get(self.position) != Some(&b'\\')
776                            || self.bytes.get(self.position + 1) != Some(&b'u')
777                        {
778                            return Err((ErrorCode::InvalidUnicodeEscape, start));
779                        }
780                        self.position += 2;
781                        let second = self.hex4(start)?;
782                        if !(0xdc00..=0xdfff).contains(&second) {
783                            return Err((ErrorCode::InvalidUnicodeEscape, start));
784                        }
785                        let scalar = 0x1_0000 + ((first - 0xd800) << 10) + (second - 0xdc00);
786                        char::from_u32(scalar).ok_or((ErrorCode::InvalidUnicodeEscape, start))?
787                    }
788                    0xdc00..=0xdfff => return Err((ErrorCode::InvalidUnicodeEscape, start)),
789                    scalar => {
790                        char::from_u32(scalar).ok_or((ErrorCode::InvalidUnicodeEscape, start))?
791                    }
792                }
793            }
794            _ => return Err((ErrorCode::InvalidEscape, start)),
795        })
796    }
797
798    fn hex4(&mut self, escape_start: usize) -> Result<u32, Failure> {
799        let digits = self
800            .bytes
801            .get(self.position..self.position + 4)
802            .ok_or((ErrorCode::InvalidUnicodeEscape, escape_start))?;
803        let mut value = 0_u32;
804        for digit in digits {
805            let nibble = char::from(*digit)
806                .to_digit(16)
807                .ok_or((ErrorCode::InvalidUnicodeEscape, escape_start))?;
808            value = value * 16 + nibble;
809        }
810        self.position += 4;
811        Ok(value)
812    }
813
814    fn array(&mut self, depth: usize) -> Result<Value, Failure> {
815        let start = self.position;
816        if depth > self.limits.max_depth {
817            return Err((ErrorCode::DepthLimit, start));
818        }
819        self.position += 1;
820        let mut items = Vec::new();
821        self.trivia()?;
822        if self.peek() == Some(b']') {
823            self.position += 1;
824            return Ok(Value::Array {
825                items,
826                span: Span {
827                    start,
828                    end: self.position,
829                },
830            });
831        }
832        loop {
833            self.trivia()?;
834            if items.len() == self.limits.max_array_items {
835                return Err((ErrorCode::ArrayLimit, self.position));
836            }
837            items.push(self.value(depth)?);
838            self.trivia()?;
839            match self.peek() {
840                Some(b',') => {
841                    let comma = self.position;
842                    self.position += 1;
843                    self.trivia()?;
844                    if self.peek() == Some(b']') {
845                        return Err((ErrorCode::TrailingComma, comma));
846                    }
847                }
848                Some(b']') => {
849                    self.position += 1;
850                    return Ok(Value::Array {
851                        items,
852                        span: Span {
853                            start,
854                            end: self.position,
855                        },
856                    });
857                }
858                None => return Err((ErrorCode::UnexpectedEnd, self.position)),
859                Some(_) => return Err((ErrorCode::ExpectedCommaOrEnd, self.position)),
860            }
861        }
862    }
863
864    fn object(&mut self, depth: usize) -> Result<Value, Failure> {
865        let start = self.position;
866        if depth > self.limits.max_depth {
867            return Err((ErrorCode::DepthLimit, start));
868        }
869        self.position += 1;
870        let mut members: Vec<Member> = Vec::new();
871        let mut keys = HashSet::new();
872        self.trivia()?;
873        if self.peek() == Some(b'}') {
874            self.position += 1;
875            return Ok(Value::Object {
876                members,
877                span: Span {
878                    start,
879                    end: self.position,
880                },
881            });
882        }
883        loop {
884            self.trivia()?;
885            let key_start = self.position;
886            match self.peek() {
887                Some(b'"') => {}
888                None => return Err((ErrorCode::UnexpectedEnd, key_start)),
889                Some(_) => return Err((ErrorCode::ExpectedKey, key_start)),
890            }
891            if members.len() == self.limits.max_object_keys {
892                return Err((ErrorCode::ObjectLimit, key_start));
893            }
894            let key = self.string()?;
895            let key_span = Span {
896                start: key_start,
897                end: self.position,
898            };
899            if !keys.insert(key.clone()) {
900                return Err((ErrorCode::DuplicateKey, key_start));
901            }
902            self.trivia()?;
903            if self.peek() != Some(b':') {
904                return Err((ErrorCode::ExpectedColon, self.position));
905            }
906            self.position += 1;
907            self.trivia()?;
908            let value = self.value(depth)?;
909            members.push(Member {
910                key,
911                key_span,
912                value,
913            });
914            self.trivia()?;
915            match self.peek() {
916                Some(b',') => {
917                    let comma = self.position;
918                    self.position += 1;
919                    self.trivia()?;
920                    if self.peek() == Some(b'}') {
921                        return Err((ErrorCode::TrailingComma, comma));
922                    }
923                }
924                Some(b'}') => {
925                    self.position += 1;
926                    return Ok(Value::Object {
927                        members,
928                        span: Span {
929                            start,
930                            end: self.position,
931                        },
932                    });
933                }
934                None => return Err((ErrorCode::UnexpectedEnd, self.position)),
935                Some(_) => return Err((ErrorCode::ExpectedCommaOrEnd, self.position)),
936            }
937        }
938    }
939}
940
941#[cfg(test)]
942mod tests;