nodedb_query/msgpack_scan/
writer.rs1use nodedb_types::InstantKind;
11
12#[inline]
14pub fn write_map_header(buf: &mut Vec<u8>, len: usize) {
15 if len < 16 {
16 buf.push(0x80 | len as u8);
17 } else if len <= u16::MAX as usize {
18 buf.push(0xDE);
19 buf.extend_from_slice(&(len as u16).to_be_bytes());
20 } else {
21 buf.push(0xDF);
22 buf.extend_from_slice(&(len as u32).to_be_bytes());
23 }
24}
25
26#[inline]
28pub fn write_array_header(buf: &mut Vec<u8>, len: usize) {
29 if len < 16 {
30 buf.push(0x90 | len as u8);
31 } else if len <= u16::MAX as usize {
32 buf.push(0xDC);
33 buf.extend_from_slice(&(len as u16).to_be_bytes());
34 } else {
35 buf.push(0xDD);
36 buf.extend_from_slice(&(len as u32).to_be_bytes());
37 }
38}
39
40#[inline]
42pub fn write_str(buf: &mut Vec<u8>, s: &str) {
43 let bytes = s.as_bytes();
44 let len = bytes.len();
45 if len < 32 {
46 buf.push(0xA0 | len as u8);
47 } else if len <= u8::MAX as usize {
48 buf.push(0xD9);
49 buf.push(len as u8);
50 } else if len <= u16::MAX as usize {
51 buf.push(0xDA);
52 buf.extend_from_slice(&(len as u16).to_be_bytes());
53 } else {
54 buf.push(0xDB);
55 buf.extend_from_slice(&(len as u32).to_be_bytes());
56 }
57 buf.extend_from_slice(bytes);
58}
59
60#[inline]
62pub fn write_i64(buf: &mut Vec<u8>, i: i64) {
63 if (0..=127).contains(&i) {
64 buf.push(i as u8);
65 } else if (-32..0).contains(&i) {
66 buf.push(i as u8); } else if i >= i8::MIN as i64 && i <= i8::MAX as i64 {
68 buf.push(0xD0);
69 buf.push(i as i8 as u8);
70 } else if i >= i16::MIN as i64 && i <= i16::MAX as i64 {
71 buf.push(0xD1);
72 buf.extend_from_slice(&(i as i16).to_be_bytes());
73 } else if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
74 buf.push(0xD2);
75 buf.extend_from_slice(&(i as i32).to_be_bytes());
76 } else {
77 buf.push(0xD3);
78 buf.extend_from_slice(&i.to_be_bytes());
79 }
80}
81
82#[inline]
84pub fn write_f64(buf: &mut Vec<u8>, f: f64) {
85 buf.push(0xCB);
86 buf.extend_from_slice(&f.to_be_bytes());
87}
88
89#[inline]
91pub fn write_bool(buf: &mut Vec<u8>, b: bool) {
92 buf.push(if b { 0xC3 } else { 0xC2 });
93}
94
95#[inline]
97pub fn write_null(buf: &mut Vec<u8>) {
98 buf.push(0xC0);
99}
100
101#[inline]
103pub fn write_instant(buf: &mut Vec<u8>, kind: InstantKind, micros: i64) {
104 nodedb_types::write_instant(buf, kind, micros);
105}
106
107#[inline]
109pub fn write_bin(buf: &mut Vec<u8>, data: &[u8]) {
110 let len = data.len();
111 if len <= u8::MAX as usize {
112 buf.push(0xC4);
113 buf.push(len as u8);
114 } else if len <= u16::MAX as usize {
115 buf.push(0xC5);
116 buf.extend_from_slice(&(len as u16).to_be_bytes());
117 } else {
118 buf.push(0xC6);
119 buf.extend_from_slice(&(len as u32).to_be_bytes());
120 }
121 buf.extend_from_slice(data);
122}
123
124#[inline]
128pub fn write_kv_str(buf: &mut Vec<u8>, key: &str, value: &str) {
129 write_str(buf, key);
130 write_str(buf, value);
131}
132
133#[inline]
135pub fn write_kv_i64(buf: &mut Vec<u8>, key: &str, value: i64) {
136 write_str(buf, key);
137 write_i64(buf, value);
138}
139
140#[inline]
142pub fn write_kv_f64(buf: &mut Vec<u8>, key: &str, value: f64) {
143 write_str(buf, key);
144 write_f64(buf, value);
145}
146
147#[inline]
149pub fn write_kv_bool(buf: &mut Vec<u8>, key: &str, value: bool) {
150 write_str(buf, key);
151 write_bool(buf, value);
152}
153
154#[inline]
160pub fn write_kv_raw(buf: &mut Vec<u8>, key: &str, raw_value: &[u8]) {
161 write_str(buf, key);
162 buf.extend_from_slice(raw_value);
163}
164
165#[inline]
167pub fn write_kv_null(buf: &mut Vec<u8>, key: &str) {
168 write_str(buf, key);
169 write_null(buf);
170}
171
172#[inline]
174pub fn write_kv_instant(buf: &mut Vec<u8>, key: &str, kind: InstantKind, micros: i64) {
175 write_str(buf, key);
176 write_instant(buf, kind, micros);
177}
178
179pub fn inject_str_field(value: &[u8], field_name: &str, field_value: &str) -> Vec<u8> {
191 if let Some((count, body_start)) = crate::msgpack_scan::reader::map_header(value, 0) {
192 if crate::msgpack_scan::extract_field(value, 0, field_name).is_some() {
193 return value.to_vec();
194 }
195 let mut buf = Vec::with_capacity(value.len() + field_name.len() + field_value.len() + 16);
196 write_map_header(&mut buf, count + 1);
197 write_kv_str(&mut buf, field_name, field_value);
198 buf.extend_from_slice(&value[body_start..]);
199 buf
200 } else {
201 let mut buf = Vec::with_capacity(value.len() + field_name.len() + field_value.len() + 16);
202 write_map_header(&mut buf, 2);
203 write_kv_str(&mut buf, field_name, field_value);
204 write_str(&mut buf, "value");
205 write_str(&mut buf, &String::from_utf8_lossy(value));
206 buf
207 }
208}
209
210pub fn merge_fields(base: &[u8], updates: &[(&str, &[u8])]) -> Vec<u8> {
216 use std::collections::HashSet;
217
218 let update_names: HashSet<&str> = updates.iter().map(|(k, _)| *k).collect();
219
220 let (count, body_start) = match crate::msgpack_scan::reader::map_header(base, 0) {
221 Some(v) => v,
222 None => {
223 let mut buf = Vec::with_capacity(updates.len() * 32);
225 write_map_header(&mut buf, updates.len());
226 for (k, v) in updates {
227 write_str(&mut buf, k);
228 buf.extend_from_slice(v);
229 }
230 return buf;
231 }
232 };
233
234 let mut kept = 0usize;
236 let mut pos = body_start;
237 for _ in 0..count {
238 let key = crate::msgpack_scan::reader::read_str(base, pos);
239 pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
240 Some(p) => p,
241 None => break,
242 };
243 pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
244 Some(p) => p,
245 None => break,
246 };
247 if let Some(k) = &key {
248 if !update_names.contains(&k[..]) {
249 kept += 1;
250 }
251 } else {
252 kept += 1;
253 }
254 }
255
256 let new_count = kept + updates.len();
257 let mut buf = Vec::with_capacity(
258 base.len()
259 + updates
260 .iter()
261 .map(|(k, v)| k.len() + v.len() + 4)
262 .sum::<usize>(),
263 );
264 write_map_header(&mut buf, new_count);
265
266 pos = body_start;
268 for _ in 0..count {
269 let key_start = pos;
270 let key = crate::msgpack_scan::reader::read_str(base, pos);
271 pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
272 Some(p) => p,
273 None => break,
274 };
275 pos = match crate::msgpack_scan::reader::skip_value(base, pos) {
276 Some(p) => p,
277 None => break,
278 };
279 if let Some(k) = &key
280 && update_names.contains(&k[..])
281 {
282 continue; }
284 buf.extend_from_slice(&base[key_start..pos]);
286 }
287
288 for (k, v) in updates {
290 write_str(&mut buf, k);
291 buf.extend_from_slice(v);
292 }
293
294 buf
295}
296
297pub fn build_str_map(pairs: &[(&str, &str)]) -> Vec<u8> {
299 let mut buf = Vec::with_capacity(pairs.len() * 32);
300 write_map_header(&mut buf, pairs.len());
301 for (k, v) in pairs {
302 write_kv_str(&mut buf, k, v);
303 }
304 buf
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn roundtrip_map() {
313 let mut buf = Vec::new();
314 write_map_header(&mut buf, 2);
315 write_kv_str(&mut buf, "name", "alice");
316 write_kv_i64(&mut buf, "age", 30);
317
318 let (count, mut pos) = crate::msgpack_scan::reader::map_header(&buf, 0).unwrap();
320 assert_eq!(count, 2);
321
322 let k1 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
323 assert_eq!(k1, "name");
324 pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
325 let v1 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
326 assert_eq!(v1, "alice");
327 pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
328
329 let k2 = crate::msgpack_scan::reader::read_str(&buf, pos).unwrap();
330 assert_eq!(k2, "age");
331 pos = crate::msgpack_scan::reader::skip_value(&buf, pos).unwrap();
332 let v2 = crate::msgpack_scan::reader::read_i64(&buf, pos).unwrap();
333 assert_eq!(v2, 30);
334 }
335
336 #[test]
337 fn write_kv_raw_splices_correctly() {
338 let mut val_buf = Vec::new();
340 write_str(&mut val_buf, "hello");
341
342 let mut buf = Vec::new();
344 write_map_header(&mut buf, 1);
345 write_kv_raw(&mut buf, "greeting", &val_buf);
346
347 let field = crate::msgpack_scan::field::extract_field(&buf, 0, "greeting").unwrap();
349 let s = crate::msgpack_scan::reader::read_str(&buf, field.0).unwrap();
350 assert_eq!(s, "hello");
351 }
352
353 #[test]
354 fn compact_integer_encoding() {
355 let mut buf = Vec::new();
357 write_i64(&mut buf, 42);
358 assert_eq!(buf, vec![42]);
359
360 buf.clear();
362 write_i64(&mut buf, -1);
363 assert_eq!(buf, vec![0xFF]);
364
365 buf.clear();
367 write_i64(&mut buf, -100);
368 assert_eq!(buf, vec![0xD0, (-100i8) as u8]);
369 }
370
371 #[test]
372 fn instant_cell_reads_back() {
373 let mut buf = Vec::new();
374 write_map_header(&mut buf, 1);
375 write_kv_instant(&mut buf, "ts", InstantKind::Naive, -42);
376
377 let field = crate::msgpack_scan::field::extract_field(&buf, 0, "ts").unwrap();
378 assert_eq!(field.1 - field.0, 10);
379 assert_eq!(
380 crate::msgpack_scan::reader::read_value(&buf, field.0),
381 Some(nodedb_types::Value::NaiveDateTime(
382 nodedb_types::NdbDateTime::from_micros(-42)
383 ))
384 );
385 }
386}