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