1use std::ops::{Index, IndexMut};
4
5#[derive(Clone, Debug, PartialEq)]
7pub enum Value {
8 Null,
10 Bool(bool),
12 Number(String),
14 String(String),
16 Array(Vec<Value>),
18 Object(Vec<(String, Value)>),
20}
21
22impl Value {
23 pub fn parse(input: &[u8]) -> Result<Self, String> {
25 let mut parser = Parser { input, pos: 0 };
26 let value = parser.value()?;
27 parser.space();
28 if parser.pos != input.len() {
29 return Err("trailing JSON data".into());
30 }
31 Ok(value)
32 }
33 pub fn to_vec(&self) -> Vec<u8> {
35 let mut out = Vec::new();
36 self.write(&mut out);
37 out
38 }
39 fn write(&self, out: &mut Vec<u8>) {
40 match self {
41 Self::Null => out.extend_from_slice(b"null"),
42 Self::Bool(v) => out.extend_from_slice(if *v { b"true" } else { b"false" }),
43 Self::Number(v) => out.extend_from_slice(v.as_bytes()),
44 Self::String(v) => write_string(out, v),
45 Self::Array(values) => {
46 out.push(b'[');
47 for (i, v) in values.iter().enumerate() {
48 if i != 0 {
49 out.push(b',');
50 }
51 v.write(out);
52 }
53 out.push(b']');
54 }
55 Self::Object(values) => {
56 out.push(b'{');
57 for (i, (k, v)) in values.iter().enumerate() {
58 if i != 0 {
59 out.push(b',');
60 }
61 write_string(out, k);
62 out.push(b':');
63 v.write(out);
64 }
65 out.push(b'}');
66 }
67 }
68 }
69 pub fn as_object(&self) -> Option<&[(String, Value)]> {
71 if let Self::Object(v) = self {
72 Some(v)
73 } else {
74 None
75 }
76 }
77 pub fn is_object(&self) -> bool {
79 matches!(self, Self::Object(_))
80 }
81 pub fn as_object_mut(&mut self) -> Option<&mut Vec<(String, Value)>> {
83 if let Self::Object(v) = self {
84 Some(v)
85 } else {
86 None
87 }
88 }
89 pub fn as_array(&self) -> Option<&[Value]> {
91 if let Self::Array(v) = self {
92 Some(v)
93 } else {
94 None
95 }
96 }
97 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
99 if let Self::Array(v) = self {
100 Some(v)
101 } else {
102 None
103 }
104 }
105 pub fn as_str(&self) -> Option<&str> {
107 if let Self::String(v) = self {
108 Some(v)
109 } else {
110 None
111 }
112 }
113 pub fn as_u64(&self) -> Option<u64> {
115 match self {
116 Self::Number(v) => v.parse().ok(),
117 _ => None,
118 }
119 }
120 pub fn as_f64(&self) -> Option<f64> {
122 match self {
123 Self::Number(v) => v.parse().ok(),
124 _ => None,
125 }
126 }
127 pub fn get(&self, key: &str) -> Option<&Value> {
129 self.as_object()?
130 .iter()
131 .find(|(k, _)| k == key)
132 .map(|(_, v)| v)
133 }
134 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
136 self.as_object_mut()?
137 .iter_mut()
138 .find(|(k, _)| k == key)
139 .map(|(_, v)| v)
140 }
141 pub fn object(entries: impl IntoIterator<Item = (impl Into<String>, Value)>) -> Self {
143 Self::Object(entries.into_iter().map(|(k, v)| (k.into(), v)).collect())
144 }
145}
146impl From<&str> for Value {
147 fn from(v: &str) -> Self {
148 Self::String(v.into())
149 }
150}
151impl From<String> for Value {
152 fn from(v: String) -> Self {
153 Self::String(v)
154 }
155}
156impl From<u64> for Value {
157 fn from(v: u64) -> Self {
158 Self::Number(v.to_string())
159 }
160}
161impl From<usize> for Value {
162 fn from(v: usize) -> Self {
163 Self::Number(v.to_string())
164 }
165}
166impl From<bool> for Value {
167 fn from(v: bool) -> Self {
168 Self::Bool(v)
169 }
170}
171static NULL: Value = Value::Null;
172impl Index<&str> for Value {
173 type Output = Value;
174 fn index(&self, k: &str) -> &Self::Output {
175 self.get(k).unwrap_or(&NULL)
176 }
177}
178impl Index<&String> for Value {
179 type Output = Value;
180 fn index(&self, k: &String) -> &Self::Output {
181 self.get(k).unwrap_or(&NULL)
182 }
183}
184impl Index<usize> for Value {
185 type Output = Value;
186 fn index(&self, i: usize) -> &Self::Output {
187 self.as_array().and_then(|v| v.get(i)).unwrap_or(&NULL)
188 }
189}
190impl IndexMut<&str> for Value {
191 fn index_mut(&mut self, k: &str) -> &mut Self::Output {
192 if !matches!(self, Self::Object(_)) {
193 *self = Self::Object(Vec::new());
194 }
195 let v = self.as_object_mut().unwrap();
196 if let Some(i) = v.iter().position(|(name, _)| name == k) {
197 &mut v[i].1
198 } else {
199 v.push((k.into(), Self::Null));
200 &mut v.last_mut().unwrap().1
201 }
202 }
203}
204impl IndexMut<usize> for Value {
205 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
206 &mut self.as_array_mut().expect("JSON value is not an array")[i]
207 }
208}
209
210fn write_string(out: &mut Vec<u8>, value: &str) {
211 out.push(b'"');
212 for ch in value.chars() {
213 match ch {
214 '"' => out.extend_from_slice(b"\\\""),
215 '\\' => out.extend_from_slice(b"\\\\"),
216 '\n' => out.extend_from_slice(b"\\n"),
217 '\r' => out.extend_from_slice(b"\\r"),
218 '\t' => out.extend_from_slice(b"\\t"),
219 c if c < ' ' => {
220 out.extend_from_slice(format!("\\u{:04x}", c as u32).as_bytes());
221 }
222 c => {
223 let mut b = [0; 4];
224 out.extend_from_slice(c.encode_utf8(&mut b).as_bytes());
225 }
226 }
227 }
228 out.push(b'"');
229}
230struct Parser<'a> {
231 input: &'a [u8],
232 pos: usize,
233}
234impl<'a> Parser<'a> {
235 fn space(&mut self) {
236 while self
237 .input
238 .get(self.pos)
239 .is_some_and(|c| c.is_ascii_whitespace())
240 {
241 self.pos += 1;
242 }
243 }
244 fn take(&mut self, c: u8) -> bool {
245 self.space();
246 if self.input.get(self.pos) == Some(&c) {
247 self.pos += 1;
248 true
249 } else {
250 false
251 }
252 }
253 fn value(&mut self) -> Result<Value, String> {
254 self.space();
255 match self.input.get(self.pos).copied() {
256 Some(b'{') => self.object(),
257 Some(b'[') => self.array(),
258 Some(b'"') => Ok(Value::String(self.string()?)),
259 Some(b't') => self.literal(b"true", Value::Bool(true)),
260 Some(b'f') => self.literal(b"false", Value::Bool(false)),
261 Some(b'n') => self.literal(b"null", Value::Null),
262 Some(b'-' | b'0'..=b'9') => self.number(),
263 _ => Err("expected JSON value".into()),
264 }
265 }
266 fn literal(&mut self, s: &[u8], v: Value) -> Result<Value, String> {
267 if self.input.get(self.pos..self.pos + s.len()) == Some(s) {
268 self.pos += s.len();
269 Ok(v)
270 } else {
271 Err("invalid JSON literal".into())
272 }
273 }
274 fn object(&mut self) -> Result<Value, String> {
275 self.pos += 1;
276 let mut o = Vec::new();
277 self.space();
278 if self.take(b'}') {
279 return Ok(Value::Object(o));
280 }
281 loop {
282 self.space();
283 if self.input.get(self.pos) != Some(&b'"') {
284 return Err("object key is not a string".into());
285 }
286 let k = self.string()?;
287 if !self.take(b':') {
288 return Err("missing object colon".into());
289 }
290 let v = self.value()?;
291 o.push((k, v));
292 if self.take(b'}') {
293 break;
294 }
295 if !self.take(b',') {
296 return Err("missing object comma".into());
297 }
298 }
299 Ok(Value::Object(o))
300 }
301 fn array(&mut self) -> Result<Value, String> {
302 self.pos += 1;
303 let mut a = Vec::new();
304 if self.take(b']') {
305 return Ok(Value::Array(a));
306 }
307 loop {
308 a.push(self.value()?);
309 if self.take(b']') {
310 break;
311 }
312 if !self.take(b',') {
313 return Err("missing array comma".into());
314 }
315 }
316 Ok(Value::Array(a))
317 }
318 fn string(&mut self) -> Result<String, String> {
319 self.pos += 1;
320 let mut out = String::new();
321 loop {
322 let b = *self.input.get(self.pos).ok_or("unterminated string")?;
323 self.pos += 1;
324 match b {
325 b'"' => return Ok(out),
326 b'\\' => {
327 let esc = *self.input.get(self.pos).ok_or("bad escape")?;
328 self.pos += 1;
329 match esc {
330 b'"' => out.push('"'),
331 b'\\' => out.push('\\'),
332 b'/' => out.push('/'),
333 b'b' => out.push('\u{8}'),
334 b'f' => out.push('\u{c}'),
335 b'n' => out.push('\n'),
336 b'r' => out.push('\r'),
337 b't' => out.push('\t'),
338 b'u' => {
339 let first = self.unicode_escape()?;
340 let scalar = match first {
341 0xd800..=0xdbff => {
342 if self.input.get(self.pos..self.pos + 2) != Some(b"\\u") {
343 return Err("unpaired high surrogate".into());
344 }
345 self.pos += 2;
346 let second = self.unicode_escape()?;
347 if !(0xdc00..=0xdfff).contains(&second) {
348 return Err("invalid low surrogate".into());
349 }
350 0x1_0000
351 + (u32::from(first - 0xd800) << 10)
352 + u32::from(second - 0xdc00)
353 }
354 0xdc00..=0xdfff => return Err("unpaired low surrogate".into()),
355 value => u32::from(value),
356 };
357 out.push(char::from_u32(scalar).ok_or("invalid unicode scalar")?);
358 }
359 _ => return Err("invalid escape".into()),
360 }
361 }
362 0..=0x1f => return Err("control character in string".into()),
363 0x20..=0x7f => out.push(char::from(b)),
364 _ => {
365 let width = match b {
369 0xc2..=0xdf => 2,
370 0xe0..=0xef => 3,
371 0xf0..=0xf4 => 4,
372 _ => return Err("invalid utf8".into()),
373 };
374 let start = self.pos - 1;
375 let encoded = self.input.get(start..start + width).ok_or("invalid utf8")?;
376 let ch = std::str::from_utf8(encoded)
377 .map_err(|_| "invalid utf8")?
378 .chars()
379 .next()
380 .ok_or("invalid utf8")?;
381 out.push(ch);
382 self.pos = start + width;
383 }
384 }
385 }
386 }
387 fn number(&mut self) -> Result<Value, String> {
388 let start = self.pos;
389 if self.input.get(self.pos) == Some(&b'-') {
390 self.pos += 1;
391 }
392 match self.input.get(self.pos) {
393 Some(b'0') => self.pos += 1,
394 Some(b'1'..=b'9') => {
395 self.pos += 1;
396 while self
397 .input
398 .get(self.pos)
399 .is_some_and(|byte| byte.is_ascii_digit())
400 {
401 self.pos += 1;
402 }
403 }
404 _ => return Err("invalid number".into()),
405 }
406 if self.input.get(self.pos) == Some(&b'.') {
407 self.pos += 1;
408 if !self
409 .input
410 .get(self.pos)
411 .is_some_and(|byte| byte.is_ascii_digit())
412 {
413 return Err("invalid number fraction".into());
414 }
415 while self
416 .input
417 .get(self.pos)
418 .is_some_and(|byte| byte.is_ascii_digit())
419 {
420 self.pos += 1;
421 }
422 }
423 if self
424 .input
425 .get(self.pos)
426 .is_some_and(|byte| matches!(byte, b'e' | b'E'))
427 {
428 self.pos += 1;
429 if self
430 .input
431 .get(self.pos)
432 .is_some_and(|byte| matches!(byte, b'+' | b'-'))
433 {
434 self.pos += 1;
435 }
436 if !self
437 .input
438 .get(self.pos)
439 .is_some_and(|byte| byte.is_ascii_digit())
440 {
441 return Err("invalid number exponent".into());
442 }
443 while self
444 .input
445 .get(self.pos)
446 .is_some_and(|byte| byte.is_ascii_digit())
447 {
448 self.pos += 1;
449 }
450 }
451 let text =
452 std::str::from_utf8(&self.input[start..self.pos]).map_err(|_| "invalid number")?;
453 Ok(Value::Number(text.into()))
454 }
455
456 fn unicode_escape(&mut self) -> Result<u16, String> {
457 let hex = self
458 .input
459 .get(self.pos..self.pos + 4)
460 .ok_or("short unicode escape")?;
461 self.pos += 4;
462 let text = std::str::from_utf8(hex).map_err(|_| "invalid unicode escape")?;
463 u16::from_str_radix(text, 16).map_err(|_| "invalid unicode escape".into())
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use super::Value;
470
471 #[test]
472 fn parses_unicode_surrogate_pairs() {
473 assert_eq!(
474 Value::parse(br#""\ud83d\ude80""#).unwrap(),
475 Value::String("🚀".into())
476 );
477 assert!(Value::parse(br#""\ud83d""#).is_err());
478 assert!(Value::parse(br#""\ude80""#).is_err());
479 }
480
481 #[test]
482 fn parses_raw_multibyte_scalars_and_rejects_malformed_bytes() {
483 let source = "\"aé\u{20ac}\u{1f680}\"";
484 assert_eq!(
485 Value::parse(source.as_bytes()).unwrap(),
486 Value::String("aé\u{20ac}\u{1f680}".into())
487 );
488 for invalid in [
489 b"\"\x80\"".as_slice(), b"\"\xc0\xaf\"".as_slice(), b"\"\xed\xa0\x80\"".as_slice(), b"\"\xf5\x80\x80\x80\"".as_slice(), b"\"\xe2\x82\"".as_slice(), ] {
495 assert!(
496 Value::parse(invalid).is_err(),
497 "{invalid:?} should be invalid"
498 );
499 }
500 }
501
502 #[test]
503 fn enforces_json_number_grammar_without_float_range_limits() {
504 assert!(Value::parse(b"123456789012345678901234567890e999999").is_ok());
505 for invalid in [
506 b"01".as_slice(),
507 b"1.".as_slice(),
508 b"1e".as_slice(),
509 b"-".as_slice(),
510 ] {
511 assert!(
512 Value::parse(invalid).is_err(),
513 "{invalid:?} should be invalid"
514 );
515 }
516 }
517}