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 };
137 reader.skip_whitespace();
138 let value = reader.value()?;
139 reader.skip_whitespace();
140 if reader.pos != reader.bytes.len() {
141 return Err(reader.error("unexpected trailing content"));
142 }
143 Ok(value)
144}
145
146struct Reader<'a> {
147 bytes: &'a [u8],
148 pos: usize,
149}
150
151impl Reader<'_> {
152 fn error(&self, detail: &str) -> Error {
153 Error {
154 detail: detail.to_string(),
155 offset: self.pos,
156 }
157 }
158
159 fn peek(&self) -> Option<u8> {
160 self.bytes.get(self.pos).copied()
161 }
162
163 fn skip_whitespace(&mut self) {
164 while matches!(self.peek(), Some(b' ' | b'\t' | b'\r' | b'\n')) {
165 self.pos += 1;
166 }
167 }
168
169 fn literal(&mut self, word: &str, value: Value) -> Result<Value, Error> {
171 if self.bytes[self.pos..].starts_with(word.as_bytes()) {
172 self.pos += word.len();
173 Ok(value)
174 } else {
175 Err(self.error(&format!("expected `{word}`")))
176 }
177 }
178
179 fn value(&mut self) -> Result<Value, Error> {
180 match self.peek() {
181 None => Err(self.error("expected a value")),
182 Some(b'{') => self.object(),
183 Some(b'[') => self.array(),
184 Some(b'"') => Ok(Value::String(self.string()?)),
185 Some(b't') => self.literal("true", Value::Bool(true)),
186 Some(b'f') => self.literal("false", Value::Bool(false)),
187 Some(b'n') => self.literal("null", Value::Null),
188 Some(_) => self.number(),
189 }
190 }
191
192 fn object(&mut self) -> Result<Value, Error> {
193 self.pos += 1; let mut members = Vec::new();
195 self.skip_whitespace();
196 if self.peek() == Some(b'}') {
197 self.pos += 1;
198 return Ok(Value::Object(members));
199 }
200 loop {
201 self.skip_whitespace();
202 if self.peek() != Some(b'"') {
203 return Err(self.error("expected a member name"));
204 }
205 let name = self.string()?;
206 self.skip_whitespace();
207 if self.peek() != Some(b':') {
208 return Err(self.error("expected `:` after a member name"));
209 }
210 self.pos += 1;
211 self.skip_whitespace();
212 members.push((name, self.value()?));
213 self.skip_whitespace();
214 match self.peek() {
215 Some(b',') => self.pos += 1,
216 Some(b'}') => {
217 self.pos += 1;
218 return Ok(Value::Object(members));
219 }
220 _ => return Err(self.error("expected `,` or `}`")),
221 }
222 }
223 }
224
225 fn array(&mut self) -> Result<Value, Error> {
226 self.pos += 1; let mut items = Vec::new();
228 self.skip_whitespace();
229 if self.peek() == Some(b']') {
230 self.pos += 1;
231 return Ok(Value::Array(items));
232 }
233 loop {
234 self.skip_whitespace();
235 items.push(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::Array(items));
242 }
243 _ => return Err(self.error("expected `,` or `]`")),
244 }
245 }
246 }
247
248 fn string(&mut self) -> Result<String, Error> {
249 self.pos += 1; let mut out = String::new();
251 loop {
252 let Some(byte) = self.peek() else {
253 return Err(self.error("unterminated string"));
254 };
255 match byte {
256 b'"' => {
257 self.pos += 1;
258 return Ok(out);
259 }
260 b'\\' => {
261 self.pos += 1;
262 self.escape(&mut out)?;
263 }
264 0x00..=0x1f => return Err(self.error("unescaped control character in string")),
265 _ => {
266 let start = self.pos;
270 self.pos += 1;
271 while matches!(self.peek(), Some(b) if b & 0xc0 == 0x80) {
272 self.pos += 1;
273 }
274 match std::str::from_utf8(&self.bytes[start..self.pos]) {
275 Ok(text) => out.push_str(text),
276 Err(_) => return Err(self.error("invalid UTF-8 in string")),
277 }
278 }
279 }
280 }
281 }
282
283 fn escape(&mut self, out: &mut String) -> Result<(), Error> {
284 let Some(byte) = self.peek() else {
285 return Err(self.error("unterminated escape sequence"));
286 };
287 self.pos += 1;
288 out.push(match byte {
289 b'"' => '"',
290 b'\\' => '\\',
291 b'/' => '/',
292 b'b' => '\u{8}',
293 b'f' => '\u{c}',
294 b'n' => '\n',
295 b'r' => '\r',
296 b't' => '\t',
297 b'u' => return self.unicode_escape(out),
298 _ => return Err(self.error("unknown escape sequence")),
299 });
300 Ok(())
301 }
302
303 fn unicode_escape(&mut self, out: &mut String) -> Result<(), Error> {
305 let high = self.hex4()?;
306 let scalar = if (0xd800..0xdc00).contains(&high) {
307 if !self.bytes[self.pos..].starts_with(b"\\u") {
308 return Err(self.error("lone high surrogate"));
309 }
310 self.pos += 2;
311 let low = self.hex4()?;
312 if !(0xdc00..0xe000).contains(&low) {
313 return Err(self.error("expected a low surrogate"));
314 }
315 0x10000 + ((high - 0xd800) << 10) + (low - 0xdc00)
316 } else if (0xdc00..0xe000).contains(&high) {
317 return Err(self.error("lone low surrogate"));
318 } else {
319 high
320 };
321 match char::from_u32(scalar) {
322 Some(c) => out.push(c),
323 None => return Err(self.error("escape is not a Unicode scalar value")),
324 }
325 Ok(())
326 }
327
328 fn hex4(&mut self) -> Result<u32, Error> {
329 let end = self.pos + 4;
330 if end > self.bytes.len() {
331 return Err(self.error("truncated `\\u` escape"));
332 }
333 let mut value = 0;
334 for &byte in &self.bytes[self.pos..end] {
335 let digit = match byte {
336 b'0'..=b'9' => u32::from(byte - b'0'),
337 b'a'..=b'f' => u32::from(byte - b'a') + 10,
338 b'A'..=b'F' => u32::from(byte - b'A') + 10,
339 _ => return Err(self.error("`\\u` escape needs four hex digits")),
340 };
341 value = value * 16 + digit;
342 }
343 self.pos = end;
344 Ok(value)
345 }
346
347 fn number(&mut self) -> Result<Value, Error> {
348 let start = self.pos;
349 if self.peek() == Some(b'-') {
350 self.pos += 1;
351 }
352 while matches!(
353 self.peek(),
354 Some(b'0'..=b'9' | b'.' | b'e' | b'E' | b'+' | b'-')
355 ) {
356 self.pos += 1;
357 }
358 let text = std::str::from_utf8(&self.bytes[start..self.pos]).unwrap_or("");
359 if let Ok(number) = text.parse::<f64>() {
360 Ok(Value::Number(number))
361 } else {
362 self.pos = start;
363 Err(self.error("expected a value"))
364 }
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371
372 #[test]
373 fn reads_the_shapes_a_dictionary_uses() {
374 let value =
375 parse(r#"{"types": {"XPN": ["FN", "ST"]}, "n": 2.5, "ok": true, "x": null}"#).unwrap();
376 assert_eq!(
377 value
378 .get("types")
379 .unwrap()
380 .get("XPN")
381 .unwrap()
382 .as_array()
383 .unwrap()[0]
384 .as_str(),
385 Some("FN")
386 );
387 assert_eq!(value.get("n"), Some(&Value::Number(2.5)));
388 assert_eq!(value.get("ok").unwrap().as_bool(), Some(true));
389 assert!(value.get("x").unwrap().is_null());
390 assert_eq!(value.get("missing"), None);
391 }
392
393 #[test]
394 fn keeps_object_order() {
395 let value = parse(r#"{"b": 1, "a": 2}"#).unwrap();
396 let names: Vec<&str> = value
397 .as_object()
398 .unwrap()
399 .iter()
400 .map(|(name, _)| name.as_str())
401 .collect();
402 assert_eq!(names, ["b", "a"]);
403 }
404
405 #[test]
406 fn resolves_escapes_including_surrogate_pairs() {
407 assert_eq!(
408 parse(r#""aé😀\n\"\\""#).unwrap().as_str(),
409 Some("aé😀\n\"\\")
410 );
411 assert_eq!(parse("\"caf\u{e9}\"").unwrap().as_str(), Some("café"));
412 }
413
414 #[test]
415 fn reports_where_the_problem_is() {
416 let error = parse(r#"{"a": 1,}"#).unwrap_err();
418 assert_eq!(error.offset, 8);
419 assert!(error.to_string().contains("byte 8"), "{error}");
420 assert!(parse(r#"{"a": 1} {"b": 2}"#).is_err());
421 assert!(parse(r#"{"a" 1}"#).is_err());
422 assert!(parse(r#""unterminated"#).is_err());
423 assert!(parse("").is_err());
424 }
425}