Skip to main content

handwritten_json/
utilities.rs

1use core::{iter::Peekable, str::Chars};
2
3use crate::{Error, Result};
4
5fn skip_whitespace(chars: &mut Peekable<Chars>) {
6    while chars
7        .peek()
8        .map(|ch| ch.is_ascii_whitespace())
9        .unwrap_or(false)
10    {
11        chars.next();
12    }
13}
14
15fn next_should_be(output: &mut String, chars: &mut Peekable<Chars>, expected: char) -> Result<()> {
16    if let Some(ch) = chars.next() {
17        if ch != expected {
18            return Err(Error::ShouldBe {
19                actual: ch,
20                expected,
21            });
22        }
23        output.push(ch);
24    }
25    Ok(())
26}
27
28fn parse_string(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
29    next_should_be(output, chars, '"')?;
30    let mut escape = false;
31    let mut matched = false;
32    for ch in chars {
33        output.push(ch);
34        if escape {
35            escape = false;
36        } else {
37            match ch {
38                '\\' => {
39                    escape = true;
40                }
41                '"' => {
42                    matched = true;
43                    break;
44                }
45                _ => {}
46            }
47        }
48    }
49    if matched {
50        Ok(())
51    } else {
52        Err(Error::MissingDoubleQuote)
53    }
54}
55
56fn parse_key(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
57    let mut is_empty = true;
58    output.push('"');
59    while let Some(ch) = chars.peek() {
60        if ch.is_ascii_alphanumeric() || *ch == '_' {
61            output.push(*ch);
62            chars.next();
63            if is_empty {
64                is_empty = false;
65            }
66        } else {
67            break;
68        }
69    }
70    if is_empty {
71        Err(Error::MissingKey)
72    } else {
73        output.push('"');
74        Ok(())
75    }
76}
77
78fn parse_nonstring(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
79    let mut is_empty = true;
80    while let Some(ch) = chars.peek() {
81        if ch.is_ascii_alphanumeric() || *ch == '+' || *ch == '-' || *ch == '.' {
82            output.push(*ch);
83            chars.next();
84            if is_empty {
85                is_empty = false;
86            }
87        } else {
88            break;
89        }
90    }
91    if is_empty {
92        Err(Error::MissingNonString)
93    } else {
94        Ok(())
95    }
96}
97
98fn parse_key_value(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
99    if chars.peek().map(|ch| *ch == '"').unwrap_or(false) {
100        parse_string(output, chars)?;
101    } else {
102        parse_key(output, chars)?;
103    }
104    skip_whitespace(chars);
105    if chars.next().map(|ch| ch == ':').unwrap_or(false) {
106        output.push(':');
107        skip_whitespace(chars);
108        parse_value(output, chars)
109    } else {
110        Err(Error::MissingColon)
111    }
112}
113
114fn parse_value(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
115    if let Some(ch) = chars.peek() {
116        match *ch {
117            '{' => parse_object(output, chars),
118            '[' => parse_array(output, chars),
119            '"' => parse_string(output, chars),
120            _ => parse_nonstring(output, chars),
121        }
122    } else {
123        Err(Error::MissingValue)
124    }
125}
126
127pub(crate) fn parse_object(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
128    next_should_be(output, chars, '{')?;
129    skip_whitespace(chars);
130    if chars.peek().map(|ch| *ch == '}').unwrap_or(false) {
131        output.push('}');
132        chars.next();
133        return Ok(());
134    }
135    parse_key_value(output, chars)?;
136    skip_whitespace(chars);
137    let mut matched = false;
138    while let Some(ch) = chars.peek() {
139        if *ch == ',' {
140            chars.next();
141            skip_whitespace(chars);
142        }
143        if chars.peek().map(|ch| *ch == '}').unwrap_or(false) {
144            output.push('}');
145            chars.next();
146            matched = true;
147            break;
148        }
149        output.push(',');
150        skip_whitespace(chars);
151        parse_key_value(output, chars)?;
152        skip_whitespace(chars);
153    }
154    if matched {
155        Ok(())
156    } else {
157        Err(Error::MissingRightBrace)
158    }
159}
160
161pub(crate) fn parse_array(output: &mut String, chars: &mut Peekable<Chars>) -> Result<()> {
162    next_should_be(output, chars, '[')?;
163    skip_whitespace(chars);
164    if chars.peek().map(|ch| *ch == ']').unwrap_or(false) {
165        output.push(']');
166        chars.next();
167        return Ok(());
168    }
169    parse_value(output, chars)?;
170    skip_whitespace(chars);
171    let mut matched = false;
172    while let Some(ch) = chars.peek() {
173        if *ch == ',' {
174            chars.next();
175            skip_whitespace(chars);
176        }
177        if chars.peek().map(|ch| *ch == ']').unwrap_or(false) {
178            output.push(']');
179            chars.next();
180            matched = true;
181            break;
182        }
183        output.push(',');
184        skip_whitespace(chars);
185        parse_value(output, chars)?;
186        skip_whitespace(chars);
187    }
188    if matched {
189        Ok(())
190    } else {
191        Err(Error::MissingRightBracket)
192    }
193}