Skip to main content

nodedb_types/json_msgpack/
writer.rs

1//! Msgpack serialization for `serde_json::Value` and `nodedb_types::Value`.
2
3use super::json_value::JsonValue;
4
5/// Serialize a `serde_json::Value` to MessagePack bytes.
6#[inline]
7pub fn json_to_msgpack(value: &serde_json::Value) -> zerompk::Result<Vec<u8>> {
8    zerompk::to_msgpack_vec(&JsonValue(value.clone()))
9}
10
11/// Serialize a `serde_json::Value` to MessagePack bytes, returning an empty
12/// msgpack map (`0x80`) on failure.
13///
14/// Suitable for filter evaluation where an empty map causes all field
15/// predicates to pass vacuously. Callers that need error propagation
16/// should use [`json_to_msgpack`] instead.
17#[inline]
18pub fn json_to_msgpack_or_empty(value: &serde_json::Value) -> Vec<u8> {
19    json_to_msgpack(value).unwrap_or_else(|_| vec![0x80])
20}
21
22/// Serialize a `nodedb_types::Value` to standard MessagePack bytes.
23///
24/// Writes standard msgpack format (fixmap 0x80-0x8F, fixstr 0xA0-0xBF, etc.)
25/// directly from `Value` — no zerompk tagged encoding.
26pub fn value_to_msgpack(value: &crate::Value) -> zerompk::Result<Vec<u8>> {
27    let mut buf = Vec::with_capacity(128);
28    write_native_value(&mut buf, value);
29    Ok(buf)
30}
31
32/// Write a `nodedb_types::Value` as standard msgpack bytes.
33fn write_native_value(buf: &mut Vec<u8>, value: &crate::Value) {
34    match value {
35        crate::Value::Null => buf.push(0xC0),
36        crate::Value::Bool(false) => buf.push(0xC2),
37        crate::Value::Bool(true) => buf.push(0xC3),
38        crate::Value::Integer(i) => write_native_int(buf, *i),
39        crate::Value::Float(f) => {
40            buf.push(0xCB);
41            buf.extend_from_slice(&f.to_be_bytes());
42        }
43        crate::Value::String(s)
44        | crate::Value::Uuid(s)
45        | crate::Value::Ulid(s)
46        | crate::Value::Regex(s) => write_native_str(buf, s),
47        crate::Value::Bytes(b) => write_native_bin(buf, b),
48        crate::Value::Array(arr) | crate::Value::Set(arr) => {
49            write_native_array_header(buf, arr.len());
50            for v in arr {
51                write_native_value(buf, v);
52            }
53        }
54        crate::Value::Object(map) => {
55            write_native_map_header(buf, map.len());
56            for (k, v) in map {
57                write_native_str(buf, k);
58                write_native_value(buf, v);
59            }
60        }
61        crate::Value::DateTime(dt) => write_native_str(buf, &dt.to_string()),
62        crate::Value::Duration(d) => write_native_str(buf, &d.to_string()),
63        crate::Value::Decimal(d) => write_native_str(buf, &d.to_string()),
64        crate::Value::Geometry(g) => {
65            if let Ok(s) = serde_json::to_string(g) {
66                write_native_str(buf, &s);
67            } else {
68                buf.push(0xC0);
69            }
70        }
71        crate::Value::Range { .. } | crate::Value::Record { .. } => buf.push(0xC0),
72    }
73}
74
75fn write_native_int(buf: &mut Vec<u8>, i: i64) {
76    if (0..=0x7F).contains(&i) {
77        buf.push(i as u8);
78    } else if (-32..0).contains(&i) {
79        buf.push(i as u8); // negative fixint
80    } else if i >= i8::MIN as i64 && i <= i8::MAX as i64 {
81        buf.push(0xD0);
82        buf.push(i as i8 as u8);
83    } else if i >= i16::MIN as i64 && i <= i16::MAX as i64 {
84        buf.push(0xD1);
85        buf.extend_from_slice(&(i as i16).to_be_bytes());
86    } else if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
87        buf.push(0xD2);
88        buf.extend_from_slice(&(i as i32).to_be_bytes());
89    } else {
90        buf.push(0xD3);
91        buf.extend_from_slice(&i.to_be_bytes());
92    }
93}
94
95fn write_native_str(buf: &mut Vec<u8>, s: &str) {
96    let len = s.len();
97    if len < 32 {
98        buf.push(0xA0 | len as u8);
99    } else if len <= u8::MAX as usize {
100        buf.push(0xD9);
101        buf.push(len as u8);
102    } else if len <= u16::MAX as usize {
103        buf.push(0xDA);
104        buf.extend_from_slice(&(len as u16).to_be_bytes());
105    } else {
106        buf.push(0xDB);
107        buf.extend_from_slice(&(len as u32).to_be_bytes());
108    }
109    buf.extend_from_slice(s.as_bytes());
110}
111
112fn write_native_bin(buf: &mut Vec<u8>, b: &[u8]) {
113    let len = b.len();
114    if len <= u8::MAX as usize {
115        buf.push(0xC4);
116        buf.push(len as u8);
117    } else if len <= u16::MAX as usize {
118        buf.push(0xC5);
119        buf.extend_from_slice(&(len as u16).to_be_bytes());
120    } else {
121        buf.push(0xC6);
122        buf.extend_from_slice(&(len as u32).to_be_bytes());
123    }
124    buf.extend_from_slice(b);
125}
126
127fn write_native_array_header(buf: &mut Vec<u8>, len: usize) {
128    if len < 16 {
129        buf.push(0x90 | len as u8);
130    } else if len <= u16::MAX as usize {
131        buf.push(0xDC);
132        buf.extend_from_slice(&(len as u16).to_be_bytes());
133    } else {
134        buf.push(0xDD);
135        buf.extend_from_slice(&(len as u32).to_be_bytes());
136    }
137}
138
139fn write_native_map_header(buf: &mut Vec<u8>, len: usize) {
140    if len < 16 {
141        buf.push(0x80 | len as u8);
142    } else if len <= u16::MAX as usize {
143        buf.push(0xDE);
144        buf.extend_from_slice(&(len as u16).to_be_bytes());
145    } else {
146        buf.push(0xDF);
147        buf.extend_from_slice(&(len as u32).to_be_bytes());
148    }
149}