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 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 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 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 #[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 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 #[test]
364 fn audit_log_preserves_low_control_bytes() {
365 let payload = "collection\x01name\x07with\x1fbells";
366 let encoded = encode(payload);
367
368 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 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}