1use crate::Value;
10
11#[derive(Clone, Debug, PartialEq)]
14pub struct JsonError {
15 pub line: usize,
16 pub col: usize,
17 pub message: String,
18}
19
20impl std::fmt::Display for JsonError {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{}:{}: {}", self.line, self.col, self.message)
23 }
24}
25
26impl std::error::Error for JsonError {}
27
28const MAX_DEPTH: usize = 128;
32
33pub fn parse(src: &str) -> Result<Value, JsonError> {
36 let mut p = Parser {
37 src: src.as_bytes(),
38 at: 0,
39 };
40 p.ws();
41 let v = p.value(0)?;
42 p.ws();
43 if p.at < p.src.len() {
44 return Err(p.err("expected the end of the document"));
45 }
46 Ok(v)
47}
48
49struct Parser<'a> {
50 src: &'a [u8],
51 at: usize,
52}
53
54impl Parser<'_> {
55 fn err(&self, message: impl Into<String>) -> JsonError {
56 let before = &self.src[..self.at.min(self.src.len())];
57 let line = before.iter().filter(|b| **b == b'\n').count() + 1;
58 let col = before.iter().rev().take_while(|b| **b != b'\n').count() + 1;
59 JsonError {
60 line,
61 col,
62 message: message.into(),
63 }
64 }
65
66 fn peek(&self) -> Option<u8> {
67 self.src.get(self.at).copied()
68 }
69
70 fn ws(&mut self) {
71 while matches!(self.peek(), Some(b' ' | b'\t' | b'\n' | b'\r')) {
72 self.at += 1;
73 }
74 }
75
76 fn eat(&mut self, lit: &str) -> Result<(), JsonError> {
77 if self.src[self.at..].starts_with(lit.as_bytes()) {
78 self.at += lit.len();
79 Ok(())
80 } else {
81 Err(self.err(format!("expected `{lit}`")))
82 }
83 }
84
85 fn value(&mut self, depth: usize) -> Result<Value, JsonError> {
86 if depth > MAX_DEPTH {
87 return Err(self.err("nested too deeply"));
88 }
89 match self.peek() {
90 Some(b'{') => self.object(depth),
91 Some(b'[') => self.array(depth),
92 Some(b'"') => Ok(Value::Str(self.string()?)),
93 Some(b't') => self.eat("true").map(|_| Value::Bool(true)),
94 Some(b'f') => self.eat("false").map(|_| Value::Bool(false)),
95 Some(b'n') => self.eat("null").map(|_| Value::Null),
96 Some(b'-' | b'0'..=b'9') => self.number(),
97 Some(_) => Err(self.err("expected a value")),
98 None => Err(self.err("expected a value, found the end")),
99 }
100 }
101
102 fn object(&mut self, depth: usize) -> Result<Value, JsonError> {
103 self.at += 1;
104 let mut out: Vec<(String, Value)> = Vec::new();
105 self.ws();
106 if self.peek() == Some(b'}') {
107 self.at += 1;
108 return Ok(Value::Map(out));
109 }
110 loop {
111 self.ws();
112 if self.peek() != Some(b'"') {
113 return Err(self.err("expected a key in double quotes"));
114 }
115 let key = self.string()?;
116 self.ws();
117 self.eat(":")?;
118 self.ws();
119 let v = self.value(depth + 1)?;
120 match out.iter_mut().find(|(k, _)| *k == key) {
121 Some(slot) => slot.1 = v,
122 None => out.push((key, v)),
123 }
124 self.ws();
125 match self.peek() {
126 Some(b',') => self.at += 1,
127 Some(b'}') => {
128 self.at += 1;
129 return Ok(Value::Map(out));
130 }
131 _ => return Err(self.err("expected `,` or `}`")),
132 }
133 }
134 }
135
136 fn array(&mut self, depth: usize) -> Result<Value, JsonError> {
137 self.at += 1;
138 let mut out = Vec::new();
139 self.ws();
140 if self.peek() == Some(b']') {
141 self.at += 1;
142 return Ok(Value::List(out));
143 }
144 loop {
145 self.ws();
146 out.push(self.value(depth + 1)?);
147 self.ws();
148 match self.peek() {
149 Some(b',') => self.at += 1,
150 Some(b']') => {
151 self.at += 1;
152 return Ok(Value::List(out));
153 }
154 _ => return Err(self.err("expected `,` or `]`")),
155 }
156 }
157 }
158
159 fn string(&mut self) -> Result<String, JsonError> {
160 self.at += 1;
161 let mut out = String::new();
162 loop {
163 let start = self.at;
164 while let Some(b) = self.peek() {
165 if b == b'"' || b == b'\\' || b < 0x20 {
166 break;
167 }
168 self.at += 1;
169 }
170 out.push_str(std::str::from_utf8(&self.src[start..self.at]).unwrap_or(""));
173 match self.peek() {
174 Some(b'"') => {
175 self.at += 1;
176 return Ok(out);
177 }
178 Some(b'\\') => {
179 self.at += 1;
180 let c = match self.peek() {
181 Some(b'"') => '"',
182 Some(b'\\') => '\\',
183 Some(b'/') => '/',
184 Some(b'b') => '\u{8}',
185 Some(b'f') => '\u{c}',
186 Some(b'n') => '\n',
187 Some(b'r') => '\r',
188 Some(b't') => '\t',
189 Some(b'u') => {
190 self.at += 1;
191 let hi = self.hex4()?;
192 let code = if (0xD800..0xDC00).contains(&hi) {
193 self.eat("\\u")?;
194 let lo = self.hex4()?;
195 if !(0xDC00..0xE000).contains(&lo) {
196 return Err(self.err("expected a low surrogate"));
197 }
198 0x10000 + ((hi - 0xD800) << 10) + (lo - 0xDC00)
199 } else {
200 hi
201 };
202 out.push(
203 char::from_u32(code).ok_or_else(|| self.err("not a character"))?,
204 );
205 continue;
206 }
207 _ => return Err(self.err("expected an escape")),
208 };
209 out.push(c);
210 self.at += 1;
211 }
212 Some(_) => return Err(self.err("a control character in a string")),
213 None => return Err(self.err("an unterminated string")),
214 }
215 }
216 }
217
218 fn hex4(&mut self) -> Result<u32, JsonError> {
219 let digits = self
220 .src
221 .get(self.at..self.at + 4)
222 .ok_or_else(|| self.err("expected four hex digits"))?;
223 let s = std::str::from_utf8(digits).map_err(|_| self.err("expected four hex digits"))?;
224 let v = u32::from_str_radix(s, 16).map_err(|_| self.err("expected four hex digits"))?;
225 self.at += 4;
226 Ok(v)
227 }
228
229 fn number(&mut self) -> Result<Value, JsonError> {
230 let start = self.at;
231 if self.peek() == Some(b'-') {
232 self.at += 1;
233 }
234 match self.peek() {
235 Some(b'0') => self.at += 1,
236 Some(b'1'..=b'9') => {
237 while matches!(self.peek(), Some(b'0'..=b'9')) {
238 self.at += 1;
239 }
240 }
241 _ => return Err(self.err("expected a digit")),
242 }
243 let mut integral = true;
244 if self.peek() == Some(b'.') {
245 integral = false;
246 self.at += 1;
247 if !matches!(self.peek(), Some(b'0'..=b'9')) {
248 return Err(self.err("expected a digit after `.`"));
249 }
250 while matches!(self.peek(), Some(b'0'..=b'9')) {
251 self.at += 1;
252 }
253 }
254 if matches!(self.peek(), Some(b'e' | b'E')) {
255 integral = false;
256 self.at += 1;
257 if matches!(self.peek(), Some(b'+' | b'-')) {
258 self.at += 1;
259 }
260 if !matches!(self.peek(), Some(b'0'..=b'9')) {
261 return Err(self.err("expected a digit in the exponent"));
262 }
263 while matches!(self.peek(), Some(b'0'..=b'9')) {
264 self.at += 1;
265 }
266 }
267 let text = std::str::from_utf8(&self.src[start..self.at]).unwrap_or("0");
268 if integral && let Ok(i) = text.parse::<i64>() {
269 return Ok(Value::Int(i));
270 }
271 text.parse::<f64>()
272 .map(Value::Float)
273 .map_err(|_| self.err("not a number"))
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn reads_every_kind_and_keeps_key_order() {
283 let v = parse(r#" { "b": [1, -2.5, 3e2, true, false, null], "a": "x\né😀", "b2": {} } "#)
284 .unwrap();
285 let Value::Map(m) = &v else { panic!() };
286 assert_eq!(m[0].0, "b");
287 assert_eq!(m[1].0, "a");
288 assert_eq!(
289 m[0].1,
290 Value::List(vec![
291 Value::Int(1),
292 Value::Float(-2.5),
293 Value::Float(300.0),
294 Value::Bool(true),
295 Value::Bool(false),
296 Value::Null
297 ])
298 );
299 assert_eq!(m[1].1, Value::Str("x\né😀".into()));
300 }
301
302 #[test]
303 fn a_repeated_key_keeps_the_last_value() {
304 let v = parse(r#"{"a": 1, "a": 2}"#).unwrap();
305 assert_eq!(v, Value::Map(vec![("a".into(), Value::Int(2))]));
306 }
307
308 #[test]
309 fn errors_say_where() {
310 let e = parse("{\n \"a\": 1,\n}").unwrap_err();
311 assert_eq!((e.line, e.col), (3, 1), "{e}");
312 assert!(parse("[1,]").is_err());
313 assert!(parse("01").is_err());
314 assert!(parse("\"a\" b").is_err());
315 assert!(
316 parse(&"[".repeat(200))
317 .unwrap_err()
318 .message
319 .contains("deeply")
320 );
321 }
322}