Skip to main content

reddb_types/
serde_json.rs

1use crate::utils::json::{parse_json, JsonValue};
2use std::collections::{BTreeMap, HashMap};
3use std::fmt;
4use std::ops::{Index, IndexMut};
5
6pub type Map<K, V> = BTreeMap<K, V>;
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum Value {
10    Null,
11    Bool(bool),
12    Integer(i64),
13    Number(f64),
14    Decimal(String),
15    String(String),
16    Array(Vec<Value>),
17    Object(Map<String, Value>),
18}
19
20impl fmt::Display for Value {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        f.write_str(&self.to_string_compact())
23    }
24}
25
26impl Value {
27    pub fn as_str(&self) -> Option<&str> {
28        match self {
29            Value::String(s) => Some(s.as_str()),
30            _ => None,
31        }
32    }
33
34    pub fn as_f64(&self) -> Option<f64> {
35        match self {
36            Value::Number(n) => Some(*n),
37            Value::Integer(n) => Some(*n as f64),
38            Value::Decimal(n) => n.parse::<f64>().ok(),
39            _ => None,
40        }
41    }
42
43    pub fn as_i64(&self) -> Option<i64> {
44        match self {
45            Value::Integer(n) => Some(*n),
46            Value::Number(n) => Some(*n as i64),
47            Value::Decimal(n) => n.parse::<i64>().ok(),
48            _ => None,
49        }
50    }
51
52    pub fn as_u64(&self) -> Option<u64> {
53        match self {
54            Value::Integer(n) if *n >= 0 => Some(*n as u64),
55            Value::Number(n) if *n >= 0.0 => Some(*n as u64),
56            Value::Decimal(n) => n.parse::<u64>().ok(),
57            _ => None,
58        }
59    }
60
61    pub fn as_bool(&self) -> Option<bool> {
62        match self {
63            Value::Bool(b) => Some(*b),
64            _ => None,
65        }
66    }
67
68    pub fn as_array(&self) -> Option<&[Value]> {
69        match self {
70            Value::Array(values) => Some(values.as_slice()),
71            _ => None,
72        }
73    }
74
75    pub fn as_object(&self) -> Option<&Map<String, Value>> {
76        match self {
77            Value::Object(map) => Some(map),
78            _ => None,
79        }
80    }
81
82    pub fn get(&self, key: &str) -> Option<&Value> {
83        if let Value::Object(map) = self {
84            map.get(key)
85        } else {
86            None
87        }
88    }
89
90    pub fn to_string_compact(&self) -> String {
91        let mut out = String::new();
92        self.write_compact(&mut out);
93        out
94    }
95
96    pub fn to_string_pretty(&self) -> String {
97        let mut out = String::new();
98        self.write_pretty(&mut out, 0);
99        out
100    }
101
102    /// Encode compact JSON, stopping before the output crosses `limit` bytes.
103    /// No successful partial document is returned.
104    pub fn to_string_compact_limited(&self, limit: usize) -> Option<String> {
105        let mut out = BoundedJsonString {
106            value: String::new(),
107            limit,
108        };
109        self.write_compact_to(&mut out).ok()?;
110        Some(out.value)
111    }
112
113    fn write_compact(&self, out: &mut String) {
114        self.write_compact_to(out)
115            .expect("writing JSON to a String cannot fail");
116    }
117
118    fn write_compact_to(&self, out: &mut impl fmt::Write) -> fmt::Result {
119        match self {
120            Value::Null => out.write_str("null")?,
121            Value::Bool(value) => out.write_str(if *value { "true" } else { "false" })?,
122            Value::Integer(value) => write!(out, "{value}")?,
123            Value::Number(value) => {
124                if value.fract() == 0.0 {
125                    write!(out, "{}", *value as i64)?;
126                } else {
127                    write!(out, "{value}")?;
128                }
129            }
130            Value::Decimal(value) => out.write_str(value)?,
131            Value::String(value) => write_quoted_string(out, value)?,
132            Value::Array(values) => {
133                out.write_char('[')?;
134                for (index, value) in values.iter().enumerate() {
135                    if index > 0 {
136                        out.write_char(',')?;
137                    }
138                    value.write_compact_to(out)?;
139                }
140                out.write_char(']')?;
141            }
142            Value::Object(values) => {
143                out.write_char('{')?;
144                for (index, (key, value)) in values.iter().enumerate() {
145                    if index > 0 {
146                        out.write_char(',')?;
147                    }
148                    write_quoted_string(out, key)?;
149                    out.write_char(':')?;
150                    value.write_compact_to(out)?;
151                }
152                out.write_char('}')?;
153            }
154        }
155        Ok(())
156    }
157
158    fn write_pretty(&self, out: &mut String, indent: usize) {
159        match self {
160            Value::Null
161            | Value::Bool(_)
162            | Value::Integer(_)
163            | Value::Number(_)
164            | Value::Decimal(_)
165            | Value::String(_) => {
166                out.push_str(&self.to_string_compact());
167            }
168            Value::Array(values) => {
169                out.push('[');
170                if !values.is_empty() {
171                    out.push('\n');
172                    for (idx, value) in values.iter().enumerate() {
173                        if idx > 0 {
174                            out.push_str(",\n");
175                        }
176                        out.push_str(&"  ".repeat(indent + 1));
177                        value.write_pretty(out, indent + 1);
178                    }
179                    out.push('\n');
180                    out.push_str(&"  ".repeat(indent));
181                }
182                out.push(']');
183            }
184            Value::Object(map) => {
185                out.push('{');
186                if !map.is_empty() {
187                    out.push('\n');
188                    for (idx, (key, value)) in map.iter().enumerate() {
189                        if idx > 0 {
190                            out.push_str(",\n");
191                        }
192                        out.push_str(&"  ".repeat(indent + 1));
193                        out.push('"');
194                        out.push_str(&escape_string(key));
195                        out.push_str("\": ");
196                        value.write_pretty(out, indent + 1);
197                    }
198                    out.push('\n');
199                    out.push_str(&"  ".repeat(indent));
200                }
201                out.push('}');
202            }
203        }
204    }
205}
206
207struct BoundedJsonString {
208    value: String,
209    limit: usize,
210}
211
212impl fmt::Write for BoundedJsonString {
213    fn write_str(&mut self, value: &str) -> fmt::Result {
214        if self
215            .value
216            .len()
217            .checked_add(value.len())
218            .is_none_or(|size| size > self.limit)
219        {
220            return Err(fmt::Error);
221        }
222        self.value.push_str(value);
223        Ok(())
224    }
225}
226
227fn write_quoted_string(out: &mut impl fmt::Write, value: &str) -> fmt::Result {
228    out.write_char('"')?;
229    for ch in value.chars() {
230        match ch {
231            '"' => out.write_str("\\\"")?,
232            '\\' => out.write_str("\\\\")?,
233            '\n' => out.write_str("\\n")?,
234            '\r' => out.write_str("\\r")?,
235            '\t' => out.write_str("\\t")?,
236            '\u{08}' => out.write_str("\\b")?,
237            '\u{0C}' => out.write_str("\\f")?,
238            ch if (ch as u32) < 0x20 => write!(out, "\\u{:04x}", ch as u32)?,
239            ch => out.write_char(ch)?,
240        }
241    }
242    out.write_char('"')
243}
244
245fn escape_string(input: &str) -> String {
246    // RFC 8259 §7: all control bytes (U+0000..U+001F), `"`, and `\` MUST be escaped.
247    // Previous version silently dropped control bytes other than \n \r \t — see
248    // F-01 in docs/security/serialization-boundary-audit-2026-05-06.md and
249    // ADR 0010 (serialization-boundary discipline).
250    use std::fmt::Write as _;
251    let mut out = String::with_capacity(input.len());
252    for ch in input.chars() {
253        match ch {
254            '"' => out.push_str("\\\""),
255            '\\' => out.push_str("\\\\"),
256            '\n' => out.push_str("\\n"),
257            '\r' => out.push_str("\\r"),
258            '\t' => out.push_str("\\t"),
259            '\u{08}' => out.push_str("\\b"),
260            '\u{0C}' => out.push_str("\\f"),
261            c if (c as u32) < 0x20 => {
262                let _ = write!(out, "\\u{:04x}", c as u32);
263            }
264            c => out.push(c),
265        }
266    }
267    out
268}
269
270#[cfg(test)]
271mod tests {
272    use super::*;
273    use crate::json;
274    use std::borrow::Cow;
275    use std::collections::HashMap;
276
277    #[test]
278    fn bounded_compact_json_matches_exact_bytes_and_rejects_every_shorter_limit() {
279        let value = Value::Object(Map::from([
280            (
281                "quoted".to_string(),
282                Value::String("\\\"\n\u{00}São Paulo".to_string()),
283            ),
284            (
285                "nested".to_string(),
286                Value::Array(vec![
287                    Value::Integer(1),
288                    Value::Bool(true),
289                    Value::Null,
290                    Value::Object(Map::from([("value".to_string(), Value::Number(1.25))])),
291                ]),
292            ),
293        ]));
294        let encoded = value.to_string_compact();
295        for limit in 0..encoded.len() {
296            assert!(value.to_string_compact_limited(limit).is_none());
297        }
298        assert_eq!(
299            value.to_string_compact_limited(encoded.len()),
300            Some(encoded)
301        );
302    }
303
304    #[test]
305    fn bounded_writer_stops_without_copying_a_large_string() {
306        let value = Value::String("x".repeat(1048576));
307        let mut out = BoundedJsonString {
308            value: String::new(),
309            limit: 64,
310        };
311        assert!(value.write_compact_to(&mut out).is_err());
312        assert!(out.value.len() <= 64);
313        assert!(out.value.capacity() <= 128);
314    }
315
316    fn encode(s: &str) -> String {
317        Value::String(s.to_string()).to_string_compact()
318    }
319
320    /// Every byte 0x00..0x20 must produce a valid JSON string that round-trips
321    /// through a real JSON parser preserving the original byte.
322    #[test]
323    fn escape_string_handles_every_control_byte() {
324        for byte in 0x00u8..0x20 {
325            let original: String = std::char::from_u32(byte as u32).unwrap().to_string();
326            let encoded = encode(&original);
327            // Must parse back to the exact same byte (NOT silently dropped).
328            let parsed: String = from_str(&encoded).unwrap_or_else(|err| {
329                panic!("byte 0x{byte:02x} encoded as {encoded:?} failed to parse: {err}")
330            });
331            assert_eq!(
332                parsed, original,
333                "byte 0x{byte:02x} did not round-trip (encoded={encoded:?})"
334            );
335        }
336    }
337
338    #[test]
339    fn escape_string_handles_standard_escapes() {
340        assert_eq!(encode("\""), "\"\\\"\"");
341        assert_eq!(encode("\\"), "\"\\\\\"");
342        assert_eq!(encode("\n"), "\"\\n\"");
343        assert_eq!(encode("\r"), "\"\\r\"");
344        assert_eq!(encode("\t"), "\"\\t\"");
345        assert_eq!(encode("\u{08}"), "\"\\b\"");
346        assert_eq!(encode("\u{0C}"), "\"\\f\"");
347    }
348
349    #[test]
350    fn escape_string_handles_mixed_payload() {
351        let input = "name=\"x\"\n\\path\t\x01end";
352        let encoded = encode(input);
353        let parsed: String = from_str(&encoded).expect("mixed payload must parse");
354        assert_eq!(parsed, input);
355    }
356
357    /// Regression test for F-01: the "self-disagreeing audit log" exploit.
358    /// An attacker writes audit data containing \x01. The old encoder
359    /// silently dropped \x01, so a downstream auditor that re-parses the
360    /// JSONL would see a different record than what was emitted. The fix
361    /// must encode \x01 as  so it survives the round trip.
362    #[test]
363    fn audit_log_preserves_low_control_bytes() {
364        let payload = "collection\x01name\x07with\x1fbells";
365        let encoded = encode(payload);
366
367        // Encoded form must contain explicit \u escapes — NOT raw control bytes,
368        // NOT silent drops.
369        assert!(
370            encoded.contains("\\u0001"),
371            "expected \\u0001 escape in {encoded:?}"
372        );
373        assert!(
374            encoded.contains("\\u0007"),
375            "expected \\u0007 escape in {encoded:?}"
376        );
377        assert!(
378            encoded.contains("\\u001f"),
379            "expected \\u001f escape in {encoded:?}"
380        );
381        assert!(
382            !encoded.contains('\x01'),
383            "raw \\x01 must not appear in encoded output"
384        );
385
386        // Round trip through the in-house parser must reproduce the original bytes.
387        let parsed: String = from_str(&encoded).expect("audit payload must parse");
388        assert_eq!(parsed, payload);
389    }
390
391    #[test]
392    fn value_accessors_indexing_and_pretty_printing_cover_all_shapes() {
393        let mut object = Map::new();
394        object.insert("null".to_string(), Value::Null);
395        object.insert("bool".to_string(), Value::Bool(true));
396        object.insert("number".to_string(), Value::Number(42.5));
397        object.insert(
398            "decimal".to_string(),
399            Value::Decimal("3.14159265358979323846".to_string()),
400        );
401        object.insert("string".to_string(), Value::String("reddb".to_string()));
402        object.insert(
403            "array".to_string(),
404            Value::Array(vec![Value::Number(1.0), Value::String("two".to_string())]),
405        );
406        let value = Value::Object(object);
407
408        assert_eq!(value.get("string").and_then(Value::as_str), Some("reddb"));
409        assert_eq!(value.get("number").and_then(Value::as_f64), Some(42.5));
410        assert_eq!(value.get("number").and_then(Value::as_i64), Some(42));
411        assert_eq!(value.get("number").and_then(Value::as_u64), Some(42));
412        assert_eq!(value.get("bool").and_then(Value::as_bool), Some(true));
413        assert_eq!(
414            value.get("array").and_then(Value::as_array).map(<[_]>::len),
415            Some(2)
416        );
417        assert_eq!(value.as_object().map(Map::len), Some(6));
418        assert_eq!(
419            value.get("decimal").and_then(Value::as_f64),
420            Some(3.141592653589793)
421        );
422        assert!(Value::Number(-1.0).as_u64().is_none());
423        assert!(Value::Null.as_str().is_none());
424
425        assert_eq!(value["missing"], Value::Null);
426        assert_eq!(value["string"], Value::String("reddb".to_string()));
427        let pretty = value.to_string_pretty();
428        assert!(pretty.contains('\n'));
429        assert!(pretty.contains("\"array\": ["));
430        assert_eq!(Value::Array(Vec::new()).to_string_pretty(), "[]");
431        assert_eq!(Value::Object(Map::new()).to_string_pretty(), "{}");
432        assert_eq!(
433            value.get("decimal").unwrap().to_string_compact(),
434            "3.14159265358979323846"
435        );
436
437        let mut created_from_index = Value::Null;
438        created_from_index["created"] = Value::Bool(true);
439        assert_eq!(created_from_index["created"], Value::Bool(true));
440    }
441
442    #[test]
443    fn json_encode_decode_traits_cover_scalars_collections_and_errors() {
444        assert_eq!(to_value(&true), Value::Bool(true));
445        assert_eq!(to_value(&-7i64), Value::Number(-7.0));
446        assert_eq!(to_value(&-3i32), Value::Number(-3.0));
447        assert_eq!(to_value(&7u8), Value::Number(7.0));
448        assert_eq!(to_value(&8u16), Value::Number(8.0));
449        assert_eq!(to_value(&9u32), Value::Number(9.0));
450        assert_eq!(to_value(&10u64), Value::Number(10.0));
451        assert_eq!(to_value(&11usize), Value::Number(11.0));
452        assert_eq!(to_value(&1.5f64), Value::Number(1.5));
453        assert_eq!(to_value(&2.5f32), Value::Number(2.5));
454        assert_eq!(to_value(&"borrowed"), Value::String("borrowed".to_string()));
455        assert_eq!(
456            to_value(&"owned".to_string()),
457            Value::String("owned".to_string())
458        );
459        let cow: Cow<'_, str> = Cow::Borrowed("cow");
460        assert_eq!(to_value(&cow), Value::String("cow".to_string()));
461        assert_eq!(
462            to_value(&vec![1u8, 2, 3]),
463            Value::Array(vec![
464                Value::Number(1.0),
465                Value::Number(2.0),
466                Value::Number(3.0)
467            ])
468        );
469        assert_eq!(
470            to_value(&[4u8, 5, 6]),
471            Value::Array(vec![
472                Value::Number(4.0),
473                Value::Number(5.0),
474                Value::Number(6.0)
475            ])
476        );
477        assert_eq!(to_value(&Some(12u16)), Value::Number(12.0));
478        assert_eq!(to_value(&Option::<u16>::None), Value::Null);
479
480        let mut hash = HashMap::new();
481        hash.insert("a".to_string(), 1u8);
482        let Value::Object(map) = to_value(&hash) else {
483            panic!("hash map should encode to object");
484        };
485        assert_eq!(map.get("a"), Some(&Value::Number(1.0)));
486
487        assert_eq!(
488            from_value::<String>(Value::String("x".to_string())).unwrap(),
489            "x"
490        );
491        assert!(from_value::<String>(Value::Bool(true)).is_err());
492        assert!(!from_value::<bool>(Value::Bool(false)).unwrap());
493        assert!(from_value::<bool>(Value::String("no".to_string())).is_err());
494        assert_eq!(from_value::<u8>(Value::Number(255.0)).unwrap(), 255);
495        assert_eq!(from_value::<u16>(Value::Number(256.0)).unwrap(), 256);
496        assert_eq!(from_value::<u32>(Value::Number(257.0)).unwrap(), 257);
497        assert_eq!(from_value::<u64>(Value::Number(258.0)).unwrap(), 258);
498        assert_eq!(from_value::<usize>(Value::Number(259.0)).unwrap(), 259);
499        assert_eq!(from_value::<i64>(Value::Number(-260.0)).unwrap(), -260);
500        assert_eq!(from_value::<i32>(Value::Number(-261.0)).unwrap(), -261);
501        assert_eq!(from_value::<f32>(Value::Number(1.25)).unwrap(), 1.25);
502        assert!(from_value::<u8>(Value::String("no".to_string())).is_err());
503        assert!(from_value::<Vec<u8>>(Value::Bool(false)).is_err());
504        assert_eq!(
505            from_value::<Vec<u8>>(Value::Array(vec![Value::Number(1.0), Value::Number(2.0)]))
506                .unwrap(),
507            vec![1, 2]
508        );
509
510        let mut object = Map::new();
511        object.insert("x".to_string(), Value::Number(7.0));
512        let decoded: HashMap<String, u8> = from_value(Value::Object(object)).unwrap();
513        assert_eq!(decoded.get("x"), Some(&7));
514        assert!(from_value::<HashMap<String, u8>>(Value::Null).is_err());
515
516        assert_eq!(from_value::<Option<u8>>(Value::Null).unwrap(), None);
517        assert_eq!(
518            from_value::<Option<u8>>(Value::Number(9.0)).unwrap(),
519            Some(9)
520        );
521        assert_eq!(
522            from_value::<[u8; 3]>(Value::Array(vec![
523                Value::Number(1.0),
524                Value::Number(2.0),
525                Value::Number(3.0),
526            ]))
527            .unwrap(),
528            [1, 2, 3]
529        );
530        assert!(from_value::<[u8; 3]>(Value::Array(vec![Value::Number(1.0)])).is_err());
531        assert!(from_value::<[u8; 3]>(Value::Null).is_err());
532    }
533
534    #[test]
535    fn string_and_byte_entry_points_round_trip_and_reject_bad_inputs() {
536        let bytes = to_vec(&vec![1u8, 2, 3]).unwrap();
537        assert_eq!(from_slice::<Vec<u8>>(&bytes).unwrap(), vec![1, 2, 3]);
538        assert!(from_slice::<Value>(&[0xff]).is_err());
539
540        let compact = to_string(&json!({ "b": true, "n": 2 })).unwrap();
541        assert_eq!(from_str::<Value>(&compact).unwrap()["b"], Value::Bool(true));
542
543        let pretty = to_string_pretty(&json!([1, 2])).unwrap();
544        assert!(pretty.contains('\n'));
545    }
546}
547
548impl From<JsonValue> for Value {
549    fn from(value: JsonValue) -> Self {
550        match value {
551            JsonValue::Null => Value::Null,
552            JsonValue::Bool(b) => Value::Bool(b),
553            JsonValue::Integer(n) => Value::Integer(n),
554            JsonValue::Number(n) => Value::Number(n),
555            JsonValue::Decimal(n) => Value::Decimal(n),
556            JsonValue::String(s) => Value::String(s),
557            JsonValue::Array(values) => Value::Array(values.into_iter().map(Value::from).collect()),
558            JsonValue::Object(entries) => {
559                let mut map = Map::new();
560                for (k, v) in entries {
561                    map.insert(k, Value::from(v));
562                }
563                Value::Object(map)
564            }
565        }
566    }
567}
568
569impl Index<&str> for Value {
570    type Output = Value;
571
572    fn index(&self, key: &str) -> &Self::Output {
573        static NULL: Value = Value::Null;
574        match self {
575            Value::Object(map) => map.get(key).unwrap_or(&NULL),
576            _ => &NULL,
577        }
578    }
579}
580
581impl IndexMut<&str> for Value {
582    fn index_mut(&mut self, key: &str) -> &mut Self::Output {
583        match self {
584            Value::Object(map) => map.entry(key.to_string()).or_insert(Value::Null),
585            _ => {
586                *self = Value::Object(Map::new());
587                match self {
588                    Value::Object(map) => map.entry(key.to_string()).or_insert(Value::Null),
589                    _ => unreachable!(),
590                }
591            }
592        }
593    }
594}
595
596pub trait JsonEncode {
597    fn to_json_value(&self) -> Value;
598}
599
600impl<T: JsonEncode + ?Sized> JsonEncode for &T {
601    fn to_json_value(&self) -> Value {
602        (*self).to_json_value()
603    }
604}
605
606pub trait JsonDecode: Sized {
607    fn from_json_value(value: Value) -> Result<Self, String>;
608}
609
610impl JsonEncode for Value {
611    fn to_json_value(&self) -> Value {
612        self.clone()
613    }
614}
615
616impl JsonDecode for Value {
617    fn from_json_value(value: Value) -> Result<Self, String> {
618        Ok(value)
619    }
620}
621
622impl JsonEncode for bool {
623    fn to_json_value(&self) -> Value {
624        Value::Bool(*self)
625    }
626}
627
628impl JsonEncode for i64 {
629    fn to_json_value(&self) -> Value {
630        Value::Number(*self as f64)
631    }
632}
633
634impl JsonEncode for i32 {
635    fn to_json_value(&self) -> Value {
636        Value::Number(*self as f64)
637    }
638}
639
640impl JsonEncode for u8 {
641    fn to_json_value(&self) -> Value {
642        Value::Number(*self as f64)
643    }
644}
645
646impl JsonEncode for u16 {
647    fn to_json_value(&self) -> Value {
648        Value::Number(*self as f64)
649    }
650}
651
652impl JsonEncode for u32 {
653    fn to_json_value(&self) -> Value {
654        Value::Number(*self as f64)
655    }
656}
657
658impl JsonEncode for u64 {
659    fn to_json_value(&self) -> Value {
660        Value::Number(*self as f64)
661    }
662}
663
664impl JsonEncode for usize {
665    fn to_json_value(&self) -> Value {
666        Value::Number(*self as f64)
667    }
668}
669
670impl JsonEncode for f64 {
671    fn to_json_value(&self) -> Value {
672        Value::Number(*self)
673    }
674}
675
676impl JsonEncode for f32 {
677    fn to_json_value(&self) -> Value {
678        Value::Number(*self as f64)
679    }
680}
681
682impl JsonEncode for String {
683    fn to_json_value(&self) -> Value {
684        Value::String(self.clone())
685    }
686}
687
688impl JsonEncode for &str {
689    fn to_json_value(&self) -> Value {
690        Value::String(self.to_string())
691    }
692}
693
694impl<'a> JsonEncode for std::borrow::Cow<'a, str> {
695    fn to_json_value(&self) -> Value {
696        Value::String(self.to_string())
697    }
698}
699
700impl<T: JsonEncode> JsonEncode for Vec<T> {
701    fn to_json_value(&self) -> Value {
702        Value::Array(self.iter().map(|v| v.to_json_value()).collect())
703    }
704}
705
706impl<T: JsonEncode> JsonEncode for [T] {
707    fn to_json_value(&self) -> Value {
708        Value::Array(self.iter().map(|v| v.to_json_value()).collect())
709    }
710}
711
712impl<T: JsonEncode> JsonEncode for Option<T> {
713    fn to_json_value(&self) -> Value {
714        match self {
715            Some(value) => value.to_json_value(),
716            None => Value::Null,
717        }
718    }
719}
720
721impl<const N: usize> JsonEncode for [u8; N] {
722    fn to_json_value(&self) -> Value {
723        Value::Array(self.iter().map(|b| Value::Number(*b as f64)).collect())
724    }
725}
726
727impl<T: JsonEncode> JsonEncode for HashMap<String, T> {
728    fn to_json_value(&self) -> Value {
729        let mut map = Map::new();
730        for (k, v) in self {
731            map.insert(k.clone(), v.to_json_value());
732        }
733        Value::Object(map)
734    }
735}
736
737impl JsonDecode for String {
738    fn from_json_value(value: Value) -> Result<Self, String> {
739        match value {
740            Value::String(s) => Ok(s),
741            _ => Err("expected string".to_string()),
742        }
743    }
744}
745
746impl JsonDecode for bool {
747    fn from_json_value(value: Value) -> Result<Self, String> {
748        match value {
749            Value::Bool(b) => Ok(b),
750            _ => Err("expected bool".to_string()),
751        }
752    }
753}
754
755impl JsonDecode for u8 {
756    fn from_json_value(value: Value) -> Result<Self, String> {
757        match value {
758            Value::Integer(n) => Ok(n as u8),
759            Value::Number(n) => Ok(n as u8),
760            _ => Err("expected number".to_string()),
761        }
762    }
763}
764
765impl JsonDecode for u16 {
766    fn from_json_value(value: Value) -> Result<Self, String> {
767        match value {
768            Value::Integer(n) => Ok(n as u16),
769            Value::Number(n) => Ok(n as u16),
770            _ => Err("expected number".to_string()),
771        }
772    }
773}
774
775impl JsonDecode for u32 {
776    fn from_json_value(value: Value) -> Result<Self, String> {
777        match value {
778            Value::Integer(n) => Ok(n as u32),
779            Value::Number(n) => Ok(n as u32),
780            _ => Err("expected number".to_string()),
781        }
782    }
783}
784
785impl JsonDecode for u64 {
786    fn from_json_value(value: Value) -> Result<Self, String> {
787        match value {
788            Value::Integer(n) => Ok(n as u64),
789            Value::Number(n) => Ok(n as u64),
790            _ => Err("expected number".to_string()),
791        }
792    }
793}
794
795impl JsonDecode for usize {
796    fn from_json_value(value: Value) -> Result<Self, String> {
797        match value {
798            Value::Integer(n) => Ok(n as usize),
799            Value::Number(n) => Ok(n as usize),
800            _ => Err("expected number".to_string()),
801        }
802    }
803}
804
805impl JsonDecode for i64 {
806    fn from_json_value(value: Value) -> Result<Self, String> {
807        match value {
808            Value::Integer(n) => Ok(n),
809            Value::Number(n) => Ok(n as i64),
810            _ => Err("expected number".to_string()),
811        }
812    }
813}
814
815impl JsonDecode for i32 {
816    fn from_json_value(value: Value) -> Result<Self, String> {
817        match value {
818            Value::Integer(n) => Ok(n as i32),
819            Value::Number(n) => Ok(n as i32),
820            _ => Err("expected number".to_string()),
821        }
822    }
823}
824
825impl JsonDecode for f32 {
826    fn from_json_value(value: Value) -> Result<Self, String> {
827        match value {
828            Value::Integer(n) => Ok(n as f32),
829            Value::Number(n) => Ok(n as f32),
830            _ => Err("expected number".to_string()),
831        }
832    }
833}
834
835impl<T: JsonDecode> JsonDecode for Vec<T> {
836    fn from_json_value(value: Value) -> Result<Self, String> {
837        match value {
838            Value::Array(values) => values.into_iter().map(T::from_json_value).collect(),
839            _ => Err("expected array".to_string()),
840        }
841    }
842}
843
844impl<T: JsonDecode> JsonDecode for HashMap<String, T> {
845    fn from_json_value(value: Value) -> Result<Self, String> {
846        match value {
847            Value::Object(map) => map
848                .into_iter()
849                .map(|(k, v)| Ok((k, T::from_json_value(v)?)))
850                .collect(),
851            _ => Err("expected object".to_string()),
852        }
853    }
854}
855
856impl<T: JsonDecode> JsonDecode for Option<T> {
857    fn from_json_value(value: Value) -> Result<Self, String> {
858        match value {
859            Value::Null => Ok(None),
860            other => Ok(Some(T::from_json_value(other)?)),
861        }
862    }
863}
864
865impl<const N: usize> JsonDecode for [u8; N] {
866    fn from_json_value(value: Value) -> Result<Self, String> {
867        match value {
868            Value::Array(values) => {
869                if values.len() != N {
870                    return Err("invalid array length".to_string());
871                }
872                let mut out = [0u8; N];
873                for (idx, val) in values.into_iter().enumerate() {
874                    out[idx] = u8::from_json_value(val)?;
875                }
876                Ok(out)
877            }
878            _ => Err("expected array".to_string()),
879        }
880    }
881}
882
883pub fn to_value<T: JsonEncode + ?Sized>(value: &T) -> Value {
884    value.to_json_value()
885}
886
887pub fn to_string<T: JsonEncode + ?Sized>(value: &T) -> Result<String, String> {
888    Ok(to_value(value).to_string_compact())
889}
890
891pub fn to_string_pretty<T: JsonEncode + ?Sized>(value: &T) -> Result<String, String> {
892    Ok(to_value(value).to_string_pretty())
893}
894
895pub fn to_vec<T: JsonEncode + ?Sized>(value: &T) -> Result<Vec<u8>, String> {
896    Ok(to_string(value)?.into_bytes())
897}
898
899pub fn from_str<T: JsonDecode>(input: &str) -> Result<T, String> {
900    let value = parse_json(input).map(Value::from)?;
901    T::from_json_value(value)
902}
903
904pub fn from_slice<T: JsonDecode>(input: &[u8]) -> Result<T, String> {
905    let s = std::str::from_utf8(input).map_err(|e| e.to_string())?;
906    from_str(s)
907}
908
909pub fn from_value<T: JsonDecode>(value: Value) -> Result<T, String> {
910    T::from_json_value(value)
911}
912
913#[macro_export]
914macro_rules! json {
915    (null) => {
916        $crate::serde_json::Value::Null
917    };
918    ([ $( $elem:expr ),* $(,)? ]) => {
919        $crate::serde_json::Value::Array(vec![ $( $crate::json!($elem) ),* ])
920    };
921    ({}) => {
922        $crate::serde_json::Value::Object($crate::serde_json::Map::new())
923    };
924    ({ $( $key:literal : $value:expr ),* $(,)? }) => {{
925        let mut map = $crate::serde_json::Map::new();
926        $( map.insert($key.to_string(), $crate::json!($value)); )*
927        $crate::serde_json::Value::Object(map)
928    }};
929    ($other:expr) => {
930        $crate::serde_json::to_value(&$other)
931    };
932}
933
934pub use crate::json;
935
936#[cfg(test)]
937mod json_macro_tests {
938    use super::Value;
939    use crate::json;
940
941    #[test]
942    fn object_macro_supports_empty_and_non_empty_objects() {
943        assert_eq!(json!({}), Value::Object(Default::default()));
944
945        let value = json!({ "name": "reddb", "ok": true });
946        let Value::Object(map) = value else {
947            panic!("non-empty object macro should produce an object");
948        };
949        assert_eq!(map.get("name"), Some(&Value::String("reddb".to_string())));
950        assert_eq!(map.get("ok"), Some(&Value::Bool(true)));
951    }
952}