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