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