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