1use std::fmt;
18
19#[derive(Debug, Clone, PartialEq)]
25pub enum Value {
26 Null,
28 Bool(bool),
30 Number(f64),
32 String(String),
34 Array(Vec<Value>),
36 Object(Vec<(String, Value)>),
38}
39
40impl Value {
41 #[must_use]
46 pub fn get(&self, key: &str) -> Option<&Value> {
47 match self {
48 Value::Object(members) => members.iter().find(|(k, _)| k == key).map(|(_, v)| v),
49 _ => None,
50 }
51 }
52
53 #[must_use]
55 pub fn as_str(&self) -> Option<&str> {
56 match self {
57 Value::String(s) => Some(s),
58 _ => None,
59 }
60 }
61
62 #[must_use]
64 pub fn as_object(&self) -> Option<&[(String, Value)]> {
65 match self {
66 Value::Object(members) => Some(members),
67 _ => None,
68 }
69 }
70
71 #[must_use]
73 pub fn as_array(&self) -> Option<&[Value]> {
74 match self {
75 Value::Array(items) => Some(items),
76 _ => None,
77 }
78 }
79
80 #[must_use]
82 pub fn as_bool(&self) -> Option<bool> {
83 match self {
84 Value::Bool(b) => Some(*b),
85 _ => None,
86 }
87 }
88
89 #[must_use]
91 pub fn is_null(&self) -> bool {
92 matches!(self, Value::Null)
93 }
94
95 #[must_use]
97 pub fn kind(&self) -> &'static str {
98 match self {
99 Value::Null => "null",
100 Value::Bool(_) => "boolean",
101 Value::Number(_) => "number",
102 Value::String(_) => "string",
103 Value::Array(_) => "array",
104 Value::Object(_) => "object",
105 }
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct Error {
112 pub detail: String,
114 pub offset: usize,
116}
117
118impl fmt::Display for Error {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 write!(f, "invalid JSON at byte {}: {}", self.offset, self.detail)
121 }
122}
123
124impl std::error::Error for Error {}
125
126pub fn parse(text: &str) -> Result<Value, Error> {
133 let mut reader = Reader {
134 bytes: text.as_bytes(),
135 pos: 0,
136 depth: 0,
137 };
138 reader.skip_whitespace();
139 let value = reader.value()?;
140 reader.skip_whitespace();
141 if reader.pos != reader.bytes.len() {
142 return Err(reader.error("unexpected trailing content"));
143 }
144 Ok(value)
145}
146
147const MAX_DEPTH: usize = 256;
155
156struct Reader<'a> {
157 bytes: &'a [u8],
158 pos: usize,
159 depth: usize,
160}
161
162impl Reader<'_> {
163 fn error(&self, detail: &str) -> Error {
164 Error {
165 detail: detail.to_string(),
166 offset: self.pos,
167 }
168 }
169
170 fn peek(&self) -> Option<u8> {
171 self.bytes.get(self.pos).copied()
172 }
173
174 fn skip_whitespace(&mut self) {
175 while matches!(self.peek(), Some(b' ' | b'\t' | b'\r' | b'\n')) {
176 self.pos += 1;
177 }
178 }
179
180 fn literal(&mut self, word: &str, value: Value) -> Result<Value, Error> {
182 if self.bytes[self.pos..].starts_with(word.as_bytes()) {
183 self.pos += word.len();
184 Ok(value)
185 } else {
186 Err(self.error(&format!("expected `{word}`")))
187 }
188 }
189
190 fn value(&mut self) -> Result<Value, Error> {
191 match self.peek() {
192 None => Err(self.error("expected a value")),
193 Some(b'{') => self.nested(Reader::object),
194 Some(b'[') => self.nested(Reader::array),
195 Some(b'"') => Ok(Value::String(self.string()?)),
196 Some(b't') => self.literal("true", Value::Bool(true)),
197 Some(b'f') => self.literal("false", Value::Bool(false)),
198 Some(b'n') => self.literal("null", Value::Null),
199 Some(_) => self.number(),
200 }
201 }
202
203 fn nested(&mut self, read: fn(&mut Self) -> Result<Value, Error>) -> Result<Value, Error> {
206 if self.depth >= MAX_DEPTH {
207 return Err(self.error(&format!("nested more than {MAX_DEPTH} deep")));
208 }
209 self.depth += 1;
210 let value = read(self);
211 self.depth -= 1;
212 value
213 }
214
215 fn object(&mut self) -> Result<Value, Error> {
216 self.pos += 1; let mut members = Vec::new();
218 self.skip_whitespace();
219 if self.peek() == Some(b'}') {
220 self.pos += 1;
221 return Ok(Value::Object(members));
222 }
223 loop {
224 self.skip_whitespace();
225 if self.peek() != Some(b'"') {
226 return Err(self.error("expected a member name"));
227 }
228 let name = self.string()?;
229 self.skip_whitespace();
230 if self.peek() != Some(b':') {
231 return Err(self.error("expected `:` after a member name"));
232 }
233 self.pos += 1;
234 self.skip_whitespace();
235 members.push((name, self.value()?));
236 self.skip_whitespace();
237 match self.peek() {
238 Some(b',') => self.pos += 1,
239 Some(b'}') => {
240 self.pos += 1;
241 return Ok(Value::Object(members));
242 }
243 _ => return Err(self.error("expected `,` or `}`")),
244 }
245 }
246 }
247
248 fn array(&mut self) -> Result<Value, Error> {
249 self.pos += 1; let mut items = Vec::new();
251 self.skip_whitespace();
252 if self.peek() == Some(b']') {
253 self.pos += 1;
254 return Ok(Value::Array(items));
255 }
256 loop {
257 self.skip_whitespace();
258 items.push(self.value()?);
259 self.skip_whitespace();
260 match self.peek() {
261 Some(b',') => self.pos += 1,
262 Some(b']') => {
263 self.pos += 1;
264 return Ok(Value::Array(items));
265 }
266 _ => return Err(self.error("expected `,` or `]`")),
267 }
268 }
269 }
270
271 fn string(&mut self) -> Result<String, Error> {
272 self.pos += 1; let mut out = String::new();
274 loop {
275 let Some(byte) = self.peek() else {
276 return Err(self.error("unterminated string"));
277 };
278 match byte {
279 b'"' => {
280 self.pos += 1;
281 return Ok(out);
282 }
283 b'\\' => {
284 self.pos += 1;
285 self.escape(&mut out)?;
286 }
287 0x00..=0x1f => return Err(self.error("unescaped control character in string")),
288 _ => {
289 let start = self.pos;
293 self.pos += 1;
294 while matches!(self.peek(), Some(b) if b & 0xc0 == 0x80) {
295 self.pos += 1;
296 }
297 match std::str::from_utf8(&self.bytes[start..self.pos]) {
298 Ok(text) => out.push_str(text),
299 Err(_) => return Err(self.error("invalid UTF-8 in string")),
300 }
301 }
302 }
303 }
304 }
305
306 fn escape(&mut self, out: &mut String) -> Result<(), Error> {
307 let Some(byte) = self.peek() else {
308 return Err(self.error("unterminated escape sequence"));
309 };
310 self.pos += 1;
311 out.push(match byte {
312 b'"' => '"',
313 b'\\' => '\\',
314 b'/' => '/',
315 b'b' => '\u{8}',
316 b'f' => '\u{c}',
317 b'n' => '\n',
318 b'r' => '\r',
319 b't' => '\t',
320 b'u' => return self.unicode_escape(out),
321 _ => return Err(self.error("unknown escape sequence")),
322 });
323 Ok(())
324 }
325
326 fn unicode_escape(&mut self, out: &mut String) -> Result<(), Error> {
328 let high = self.hex4()?;
329 let scalar = if (0xd800..0xdc00).contains(&high) {
330 if !self.bytes[self.pos..].starts_with(b"\\u") {
331 return Err(self.error("lone high surrogate"));
332 }
333 self.pos += 2;
334 let low = self.hex4()?;
335 if !(0xdc00..0xe000).contains(&low) {
336 return Err(self.error("expected a low surrogate"));
337 }
338 0x10000 + ((high - 0xd800) << 10) + (low - 0xdc00)
339 } else if (0xdc00..0xe000).contains(&high) {
340 return Err(self.error("lone low surrogate"));
341 } else {
342 high
343 };
344 match char::from_u32(scalar) {
345 Some(c) => out.push(c),
346 None => return Err(self.error("escape is not a Unicode scalar value")),
347 }
348 Ok(())
349 }
350
351 fn hex4(&mut self) -> Result<u32, Error> {
352 let end = self.pos + 4;
353 if end > self.bytes.len() {
354 return Err(self.error("truncated `\\u` escape"));
355 }
356 let mut value = 0;
357 for &byte in &self.bytes[self.pos..end] {
358 let digit = match byte {
359 b'0'..=b'9' => u32::from(byte - b'0'),
360 b'a'..=b'f' => u32::from(byte - b'a') + 10,
361 b'A'..=b'F' => u32::from(byte - b'A') + 10,
362 _ => return Err(self.error("`\\u` escape needs four hex digits")),
363 };
364 value = value * 16 + digit;
365 }
366 self.pos = end;
367 Ok(value)
368 }
369
370 fn number(&mut self) -> Result<Value, Error> {
371 let start = self.pos;
372 if self.peek() == Some(b'-') {
373 self.pos += 1;
374 }
375 while matches!(
376 self.peek(),
377 Some(b'0'..=b'9' | b'.' | b'e' | b'E' | b'+' | b'-')
378 ) {
379 self.pos += 1;
380 }
381 let text = std::str::from_utf8(&self.bytes[start..self.pos]).unwrap_or("");
382 if let Ok(number) = text.parse::<f64>() {
383 Ok(Value::Number(number))
384 } else {
385 self.pos = start;
386 Err(self.error("expected a value"))
387 }
388 }
389}
390
391#[cfg(test)]
392mod tests {
393 use super::*;
394
395 #[test]
396 fn reads_the_shapes_a_dictionary_uses() {
397 let value =
398 parse(r#"{"types": {"XPN": ["FN", "ST"]}, "n": 2.5, "ok": true, "x": null}"#).unwrap();
399 assert_eq!(
400 value
401 .get("types")
402 .unwrap()
403 .get("XPN")
404 .unwrap()
405 .as_array()
406 .unwrap()[0]
407 .as_str(),
408 Some("FN")
409 );
410 assert_eq!(value.get("n"), Some(&Value::Number(2.5)));
411 assert_eq!(value.get("ok").unwrap().as_bool(), Some(true));
412 assert!(value.get("x").unwrap().is_null());
413 assert_eq!(value.get("missing"), None);
414 }
415
416 #[test]
417 fn keeps_object_order() {
418 let value = parse(r#"{"b": 1, "a": 2}"#).unwrap();
419 let names: Vec<&str> = value
420 .as_object()
421 .unwrap()
422 .iter()
423 .map(|(name, _)| name.as_str())
424 .collect();
425 assert_eq!(names, ["b", "a"]);
426 }
427
428 #[test]
429 fn resolves_escapes_including_surrogate_pairs() {
430 assert_eq!(
431 parse(r#""aé😀\n\"\\""#).unwrap().as_str(),
432 Some("aé😀\n\"\\")
433 );
434 assert_eq!(parse("\"caf\u{e9}\"").unwrap().as_str(), Some("café"));
435 }
436
437 #[test]
438 fn reports_where_the_problem_is() {
439 let error = parse(r#"{"a": 1,}"#).unwrap_err();
441 assert_eq!(error.offset, 8);
442 assert!(error.to_string().contains("byte 8"), "{error}");
443 assert!(parse(r#"{"a": 1} {"b": 2}"#).is_err());
444 assert!(parse(r#"{"a" 1}"#).is_err());
445 assert!(parse(r#""unterminated"#).is_err());
446 assert!(parse("").is_err());
447 }
448
449 #[test]
450 fn nesting_past_the_limit_is_an_error_not_a_stack_overflow() {
451 let deep_objects = format!("{}1{}", "{\"a\":".repeat(1000), "}".repeat(1000));
455 let deep_arrays = format!("{}1{}", "[".repeat(1000), "]".repeat(1000));
456 for text in [deep_objects, deep_arrays] {
457 let error = parse(&text).unwrap_err();
458 assert!(error.detail.contains("nested more than"), "{error}");
459 }
460 }
461
462 #[test]
463 fn ordinary_nesting_depth_still_reads() {
464 let depth = 64;
465 let text = format!("{}1{}", "[".repeat(depth), "]".repeat(depth));
466 assert!(parse(&text).is_ok());
467 }
468}