handwritten_json/
utilities.rs1use 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}