1use std::fmt;
5
6#[derive(Clone, Debug, PartialEq)]
8pub enum JsonValue {
9 Null,
10 Bool(bool),
11 Number(f64),
12 String(String),
13 Array(Vec<JsonValue>),
14 Object(Vec<(String, JsonValue)>),
15}
16
17impl JsonValue {
18 pub fn as_str(&self) -> Option<&str> {
20 match self {
21 JsonValue::String(s) => Some(s.as_str()),
22 _ => None,
23 }
24 }
25
26 pub fn as_f64(&self) -> Option<f64> {
28 match self {
29 JsonValue::Number(n) => Some(*n),
30 _ => None,
31 }
32 }
33
34 pub fn as_bool(&self) -> Option<bool> {
36 match self {
37 JsonValue::Bool(b) => Some(*b),
38 _ => None,
39 }
40 }
41
42 pub fn as_array(&self) -> Option<&[JsonValue]> {
44 match self {
45 JsonValue::Array(items) => Some(items.as_slice()),
46 _ => None,
47 }
48 }
49
50 pub fn as_array_mut(&mut self) -> Option<&mut Vec<JsonValue>> {
52 match self {
53 JsonValue::Array(items) => Some(items),
54 _ => None,
55 }
56 }
57
58 pub fn as_object(&self) -> Option<&[(String, JsonValue)]> {
60 match self {
61 JsonValue::Object(entries) => Some(entries.as_slice()),
62 _ => None,
63 }
64 }
65
66 pub fn as_object_mut(&mut self) -> Option<&mut Vec<(String, JsonValue)>> {
68 match self {
69 JsonValue::Object(entries) => Some(entries),
70 _ => None,
71 }
72 }
73
74 pub fn get(&self, key: &str) -> Option<&JsonValue> {
76 if let JsonValue::Object(entries) = self {
77 for (k, v) in entries {
78 if k == key {
79 return Some(v);
80 }
81 }
82 }
83 None
84 }
85
86 pub fn get_mut(&mut self, key: &str) -> Option<&mut JsonValue> {
88 if let JsonValue::Object(entries) = self {
89 for (k, v) in entries.iter_mut() {
90 if k == key {
91 return Some(v);
92 }
93 }
94 }
95 None
96 }
97
98 pub fn object(entries: Vec<(String, JsonValue)>) -> JsonValue {
100 JsonValue::Object(entries)
101 }
102
103 pub fn array(items: Vec<JsonValue>) -> JsonValue {
105 JsonValue::Array(items)
106 }
107
108 #[deprecated(
120 note = "Use crate::serde_json::Value::to_string_compact for boundary emission; see ADR 0010 / issue #177"
121 )]
122 pub fn to_json_string(&self) -> String {
123 let mut out = String::new();
124 self.write_json(&mut out);
125 out
126 }
127
128 fn write_json(&self, out: &mut String) {
129 match self {
130 JsonValue::Null => out.push_str("null"),
131 JsonValue::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
132 JsonValue::Number(n) => {
133 if n.fract() == 0.0 {
134 out.push_str(&format!("{}", *n as i64));
135 } else {
136 out.push_str(&format!("{}", n));
137 }
138 }
139 JsonValue::String(s) => {
140 out.push('"');
141 for ch in s.chars() {
142 match ch {
143 '"' => out.push_str("\\\""),
144 '\\' => out.push_str("\\\\"),
145 '\n' => out.push_str("\\n"),
146 '\r' => out.push_str("\\r"),
147 '\t' => out.push_str("\\t"),
148 c if c.is_control() => {
149 out.push_str(&format!("\\u{:04x}", c as u32));
150 }
151 c => out.push(c),
152 }
153 }
154 out.push('"');
155 }
156 JsonValue::Array(items) => {
157 out.push('[');
158 for (idx, item) in items.iter().enumerate() {
159 if idx > 0 {
160 out.push(',');
161 }
162 item.write_json(out);
163 }
164 out.push(']');
165 }
166 JsonValue::Object(entries) => {
167 out.push('{');
168 for (idx, (key, value)) in entries.iter().enumerate() {
169 if idx > 0 {
170 out.push(',');
171 }
172 JsonValue::String(key.clone()).write_json(out);
173 out.push(':');
174 value.write_json(out);
175 }
176 out.push('}');
177 }
178 }
179 }
180}
181
182impl From<&str> for JsonValue {
183 fn from(value: &str) -> JsonValue {
184 JsonValue::String(value.to_string())
185 }
186}
187
188impl From<String> for JsonValue {
189 fn from(value: String) -> JsonValue {
190 JsonValue::String(value)
191 }
192}
193
194impl From<bool> for JsonValue {
195 fn from(value: bool) -> JsonValue {
196 JsonValue::Bool(value)
197 }
198}
199
200impl From<f64> for JsonValue {
201 fn from(value: f64) -> JsonValue {
202 JsonValue::Number(value)
203 }
204}
205
206impl From<i64> for JsonValue {
207 fn from(value: i64) -> JsonValue {
208 JsonValue::Number(value as f64)
209 }
210}
211
212impl From<usize> for JsonValue {
213 fn from(value: usize) -> JsonValue {
214 JsonValue::Number(value as f64)
215 }
216}
217
218impl fmt::Display for JsonValue {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 #[allow(deprecated)]
225 let s = self.to_json_string();
226 write!(f, "{s}")
227 }
228}
229
230pub struct JsonParser<'a> {
232 input: &'a [u8],
233 pos: usize,
234}
235
236impl<'a> JsonParser<'a> {
237 pub fn new(input: &'a str) -> Self {
239 Self {
240 input: input.as_bytes(),
241 pos: 0,
242 }
243 }
244
245 pub fn parse_value(&mut self) -> Result<JsonValue, String> {
247 self.skip_whitespace();
248 if self.eof() {
249 return Err("unexpected end of input".to_string());
250 }
251 let ch = self.current_char();
252 match ch {
253 b'n' => self.parse_null(),
254 b't' | b'f' => self.parse_bool(),
255 b'-' | b'0'..=b'9' => self.parse_number(),
256 b'"' => self.parse_string().map(JsonValue::String),
257 b'[' => self.parse_array(),
258 b'{' => self.parse_object(),
259 _ => Err(format!("unexpected character '{}'", ch as char)),
260 }
261 }
262
263 fn parse_null(&mut self) -> Result<JsonValue, String> {
264 self.expect_bytes(b"null")?;
265 Ok(JsonValue::Null)
266 }
267
268 fn parse_bool(&mut self) -> Result<JsonValue, String> {
269 if self.matches_bytes(b"true") {
270 self.pos += 4;
271 Ok(JsonValue::Bool(true))
272 } else if self.matches_bytes(b"false") {
273 self.pos += 5;
274 Ok(JsonValue::Bool(false))
275 } else {
276 Err("invalid boolean literal".to_string())
277 }
278 }
279
280 fn parse_number(&mut self) -> Result<JsonValue, String> {
281 let start = self.pos;
282 if self.current_char() == b'-' {
283 self.pos += 1;
284 }
285 if self.eof() {
286 return Err("invalid number literal".to_string());
287 }
288
289 match self.current_char() {
290 b'0' => {
291 self.pos += 1;
292 }
293 b'1'..=b'9' => {
294 self.pos += 1;
295 while !self.eof() && self.current_char().is_ascii_digit() {
296 self.pos += 1;
297 }
298 }
299 _ => return Err("invalid number literal".to_string()),
300 }
301
302 if !self.eof() && self.current_char() == b'.' {
303 self.pos += 1;
304 if self.eof() || !self.current_char().is_ascii_digit() {
305 return Err("invalid number literal".to_string());
306 }
307 while !self.eof() && self.current_char().is_ascii_digit() {
308 self.pos += 1;
309 }
310 }
311
312 if !self.eof() && (self.current_char() == b'e' || self.current_char() == b'E') {
313 self.pos += 1;
314 if !self.eof() && (self.current_char() == b'+' || self.current_char() == b'-') {
315 self.pos += 1;
316 }
317 if self.eof() || !self.current_char().is_ascii_digit() {
318 return Err("invalid number literal".to_string());
319 }
320 while !self.eof() && self.current_char().is_ascii_digit() {
321 self.pos += 1;
322 }
323 }
324
325 let slice = &self.input[start..self.pos];
326 let s = std::str::from_utf8(slice).map_err(|_| "invalid UTF-8 in number".to_string())?;
327 let value = s
328 .parse::<f64>()
329 .map_err(|_| "failed to parse number".to_string())?;
330 Ok(JsonValue::Number(value))
331 }
332
333 fn parse_string(&mut self) -> Result<String, String> {
334 self.expect_char(b'"')?;
335 let mut result = String::new();
336 while !self.eof() {
337 let ch = self.current_char();
338 match ch {
339 b'"' => {
340 self.pos += 1;
341 return Ok(result);
342 }
343 b'\\' => {
344 self.pos += 1;
345 if self.eof() {
346 return Err("unexpected end of input in escape".to_string());
347 }
348 let esc = self.current_char();
349 self.pos += 1;
350 match esc {
351 b'"' => result.push('"'),
352 b'\\' => result.push('\\'),
353 b'/' => result.push('/'),
354 b'b' => result.push('\x08'),
355 b'f' => result.push('\x0c'),
356 b'n' => result.push('\n'),
357 b'r' => result.push('\r'),
358 b't' => result.push('\t'),
359 b'u' => {
360 let code = self.parse_unicode_escape()?;
366 if (0xD800..=0xDBFF).contains(&code) {
367 if self.pos + 2 > self.input.len()
370 || self.input[self.pos] != b'\\'
371 || self.input[self.pos + 1] != b'u'
372 {
373 return Err(
374 "expected low surrogate after high surrogate".to_string()
375 );
376 }
377 self.pos += 2;
378 let low = self.parse_unicode_escape()?;
379 if !(0xDC00..=0xDFFF).contains(&low) {
380 return Err("invalid low surrogate".to_string());
381 }
382 let scalar = 0x10000 + (((code - 0xD800) << 10) | (low - 0xDC00));
383 if let Some(chr) = char::from_u32(scalar) {
384 result.push(chr);
385 } else {
386 return Err("invalid unicode escape".to_string());
387 }
388 } else if (0xDC00..=0xDFFF).contains(&code) {
389 return Err(
390 "unexpected low surrogate without preceding high surrogate"
391 .to_string(),
392 );
393 } else if let Some(chr) = char::from_u32(code) {
394 result.push(chr);
395 } else {
396 return Err("invalid unicode escape".to_string());
397 }
398 }
399 _ => return Err("invalid escape sequence".to_string()),
400 }
401 }
402 _ if ch < 0x80 => {
403 self.pos += 1;
405 result.push(ch as char);
406 }
407 _ => {
408 let next = std::str::from_utf8(&self.input[self.pos..])
417 .map_err(|_| "invalid utf-8 in string body".to_string())?
418 .chars()
419 .next()
420 .ok_or_else(|| "unterminated string literal".to_string())?;
421 self.pos += next.len_utf8();
422 result.push(next);
423 }
424 }
425 }
426 Err("unterminated string literal".to_string())
427 }
428
429 fn parse_unicode_escape(&mut self) -> Result<u32, String> {
430 if self.pos + 4 > self.input.len() {
431 return Err("invalid unicode escape".to_string());
432 }
433 let mut value = 0u32;
434 for _ in 0..4 {
435 let ch = self.current_char();
436 self.pos += 1;
437 value <<= 4;
438 value |= match ch {
439 b'0'..=b'9' => (ch - b'0') as u32,
440 b'a'..=b'f' => (ch - b'a' + 10) as u32,
441 b'A'..=b'F' => (ch - b'A' + 10) as u32,
442 _ => return Err("invalid unicode escape".to_string()),
443 };
444 }
445 Ok(value)
446 }
447
448 fn parse_array(&mut self) -> Result<JsonValue, String> {
449 self.expect_char(b'[')?;
450 let mut items = Vec::new();
451 self.skip_whitespace();
452 if self.peek_char() == Some(b']') {
453 self.pos += 1;
454 return Ok(JsonValue::Array(items));
455 }
456 loop {
457 let value = self.parse_value()?;
458 items.push(value);
459 self.skip_whitespace();
460 match self.peek_char() {
461 Some(b',') => {
462 self.pos += 1;
463 }
464 Some(b']') => {
465 self.pos += 1;
466 break;
467 }
468 _ => return Err("expected ',' or ']' in array".to_string()),
469 }
470 }
471 Ok(JsonValue::Array(items))
472 }
473
474 fn parse_object(&mut self) -> Result<JsonValue, String> {
475 self.expect_char(b'{')?;
476 let mut entries = Vec::new();
477 self.skip_whitespace();
478 if self.peek_char() == Some(b'}') {
479 self.pos += 1;
480 return Ok(JsonValue::Object(entries));
481 }
482 loop {
483 self.skip_whitespace();
484 let key = self.parse_string()?;
485 self.skip_whitespace();
486 self.expect_char(b':')?;
487 let value = self.parse_value()?;
488 entries.push((key, value));
489 self.skip_whitespace();
490 match self.peek_char() {
491 Some(b',') => {
492 self.pos += 1;
493 }
494 Some(b'}') => {
495 self.pos += 1;
496 break;
497 }
498 _ => return Err("expected ',' or '}' in object".to_string()),
499 }
500 }
501 Ok(JsonValue::Object(entries))
502 }
503
504 fn skip_whitespace(&mut self) {
505 while !self.eof() {
506 match self.current_char() {
507 b' ' | b'\n' | b'\r' | b'\t' => self.pos += 1,
508 _ => break,
509 }
510 }
511 }
512
513 fn expect_bytes(&mut self, expected: &[u8]) -> Result<(), String> {
514 if self.remaining().starts_with(expected) {
515 self.pos += expected.len();
516 Ok(())
517 } else {
518 Err("unexpected token".to_string())
519 }
520 }
521
522 fn matches_bytes(&self, expected: &[u8]) -> bool {
523 self.remaining().starts_with(expected)
524 }
525
526 fn expect_char(&mut self, expected: u8) -> Result<(), String> {
527 if self.peek_char() == Some(expected) {
528 self.pos += 1;
529 Ok(())
530 } else {
531 Err(format!("expected '{}'", expected as char))
532 }
533 }
534
535 fn peek_char(&self) -> Option<u8> {
536 if self.pos >= self.input.len() {
537 None
538 } else {
539 Some(self.input[self.pos])
540 }
541 }
542
543 fn current_char(&self) -> u8 {
544 self.input[self.pos]
545 }
546
547 fn remaining(&self) -> &[u8] {
548 &self.input[self.pos..]
549 }
550
551 fn eof(&self) -> bool {
552 self.pos >= self.input.len()
553 }
554}
555
556pub fn parse_json(input: &str) -> Result<JsonValue, String> {
558 let mut parser = JsonParser::new(input);
559 let value = parser.parse_value()?;
560 parser.skip_whitespace();
561 if parser.eof() {
562 Ok(value)
563 } else {
564 Err("unexpected trailing data".to_string())
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571
572 #[test]
573 fn parse_simple_object() {
574 let json = r#"{"name":"reddb","active":true,"count":3}"#;
575 let value = parse_json(json).unwrap();
576 let obj = value.as_object().unwrap();
577 assert_eq!(obj.len(), 3);
578 }
579
580 #[test]
581 fn parse_nested_array() {
582 let json = r#"{"items":[1,2,{"flag":false}]}"#;
583 let value = parse_json(json).unwrap();
584 assert!(value.get("items").unwrap().as_array().is_some());
585 }
586
587 #[test]
588 fn stringify_roundtrip() {
589 let json = r#"{"message":"hello","value":42}"#;
590 let value = parse_json(json).unwrap();
591 #[allow(deprecated)]
592 let output = value.to_json_string();
593 assert!(output.contains("hello"));
594 }
595}