1use std::str;
6
7use super::tags::*;
8
9pub fn read_f64(buf: &[u8], offset: usize) -> Option<f64> {
12 let tag = get(buf, offset)?;
13 match tag {
14 0x00..=0x7f => Some(tag as f64),
16 0xe0..=0xff => Some((tag as i8) as f64),
18 FLOAT64 => {
19 let bits = read_u64_be(buf, offset + 1)?;
20 Some(f64::from_bits(bits))
21 }
22 FLOAT32 => {
23 let bits = read_u32_be(buf, offset + 1)?;
24 Some(f32::from_bits(bits) as f64)
25 }
26 UINT8 => Some(get(buf, offset + 1)? as f64),
27 UINT16 => Some(read_u16_be(buf, offset + 1)? as f64),
28 UINT32 => Some(read_u32_be(buf, offset + 1)? as f64),
29 UINT64 => Some(read_u64_be(buf, offset + 1)? as f64),
30 INT8 => Some(get(buf, offset + 1)? as i8 as f64),
31 INT16 => Some(read_u16_be(buf, offset + 1)? as i16 as f64),
32 INT32 => Some(read_u32_be(buf, offset + 1)? as i32 as f64),
33 INT64 => Some(read_u64_be(buf, offset + 1)? as i64 as f64),
34 _ => None,
35 }
36}
37
38pub fn read_i64(buf: &[u8], offset: usize) -> Option<i64> {
42 i64::try_from(read_integer(buf, offset)?).ok()
43}
44
45pub fn read_integer(buf: &[u8], offset: usize) -> Option<i128> {
48 let tag = get(buf, offset)?;
49 match tag {
50 0x00..=0x7f => Some(i128::from(tag)),
51 0xe0..=0xff => Some(i128::from(tag as i8)),
52 UINT8 => Some(i128::from(get(buf, offset + 1)?)),
53 UINT16 => Some(i128::from(read_u16_be(buf, offset + 1)?)),
54 UINT32 => Some(i128::from(read_u32_be(buf, offset + 1)?)),
55 UINT64 => Some(i128::from(read_u64_be(buf, offset + 1)?)),
56 INT8 => Some(i128::from(get(buf, offset + 1)? as i8)),
57 INT16 => Some(i128::from(read_u16_be(buf, offset + 1)? as i16)),
58 INT32 => Some(i128::from(read_u32_be(buf, offset + 1)? as i32)),
59 INT64 => Some(i128::from(read_u64_be(buf, offset + 1)? as i64)),
60 _ => None,
61 }
62}
63
64pub(crate) fn read_numeric(buf: &[u8], offset: usize) -> Option<crate::numeric_cmp::Numeric> {
67 use crate::numeric_cmp::Numeric;
68 match read_integer(buf, offset) {
69 Some(i) => Some(Numeric::Int(i)),
70 None => match get(buf, offset)? {
71 FLOAT32 | FLOAT64 => read_f64(buf, offset).map(Numeric::Float),
72 _ => None,
73 },
74 }
75}
76
77pub fn read_str(buf: &[u8], offset: usize) -> Option<&str> {
81 let (start, len) = str_bounds(buf, offset)?;
82 let bytes = buf.get(start..start + len)?;
83 str::from_utf8(bytes).ok()
84}
85
86pub fn read_str_advance<'a>(buf: &'a [u8], off: &mut usize) -> Option<&'a str> {
89 let (start, len) = str_bounds(buf, *off)?;
90 let bytes = buf.get(start..start + len)?;
91 let s = str::from_utf8(bytes).ok()?;
92 *off = start + len;
93 Some(s)
94}
95
96pub fn read_bin_advance<'a>(buf: &'a [u8], off: &mut usize) -> Option<&'a [u8]> {
100 let tag = get(buf, *off)?;
101 let (len, header) = match tag {
102 BIN8 => (get(buf, *off + 1)? as usize, 2),
103 BIN16 => (read_u16_be(buf, *off + 1)? as usize, 3),
104 BIN32 => (read_u32_be(buf, *off + 1)? as usize, 5),
105 _ => return None,
106 };
107 let start = *off + header;
108 let end = start + len;
109 let data = buf.get(start..end)?;
110 *off = end;
111 Some(data)
112}
113
114pub fn read_u32_advance(buf: &[u8], off: &mut usize) -> Option<u32> {
118 let tag = get(buf, *off)?;
119 match tag {
120 0x00..=0x7f => {
121 *off += 1;
122 Some(tag as u32)
123 }
124 UINT8 => {
125 let v = get(buf, *off + 1)? as u32;
126 *off += 2;
127 Some(v)
128 }
129 UINT16 => {
130 let v = read_u16_be(buf, *off + 1)? as u32;
131 *off += 3;
132 Some(v)
133 }
134 UINT32 => {
135 let v = read_u32_be(buf, *off + 1)?;
136 *off += 5;
137 Some(v)
138 }
139 _ => None,
140 }
141}
142
143pub(crate) fn str_bounds(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
146 let tag = get(buf, offset)?;
147 match tag {
148 0xa0..=0xbf => {
149 let len = (tag & 0x1f) as usize;
150 Some((offset + 1, len))
151 }
152 STR8 => {
153 let len = get(buf, offset + 1)? as usize;
154 Some((offset + 2, len))
155 }
156 STR16 => {
157 let len = read_u16_be(buf, offset + 1)? as usize;
158 Some((offset + 3, len))
159 }
160 STR32 => {
161 let len = read_u32_be(buf, offset + 1)? as usize;
162 Some((offset + 5, len))
163 }
164 _ => None,
165 }
166}
167
168pub fn read_bool(buf: &[u8], offset: usize) -> Option<bool> {
170 match get(buf, offset)? {
171 TRUE => Some(true),
172 FALSE => Some(false),
173 _ => None,
174 }
175}
176
177pub fn read_null(buf: &[u8], offset: usize) -> bool {
179 get(buf, offset) == Some(NIL)
180}
181
182pub fn map_header(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
185 let tag = get(buf, offset)?;
186 match tag {
187 0x80..=0x8f => Some(((tag & 0x0f) as usize, offset + 1)),
188 MAP16 => Some((read_u16_be(buf, offset + 1)? as usize, offset + 3)),
189 MAP32 => Some((read_u32_be(buf, offset + 1)? as usize, offset + 5)),
190 _ => None,
191 }
192}
193
194pub fn array_header(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
197 let tag = get(buf, offset)?;
198 match tag {
199 0x90..=0x9f => Some(((tag & 0x0f) as usize, offset + 1)),
200 ARRAY16 => Some((read_u16_be(buf, offset + 1)? as usize, offset + 3)),
201 ARRAY32 => Some((read_u32_be(buf, offset + 1)? as usize, offset + 5)),
202 _ => None,
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use crate::msgpack_scan::reader::skip_value;
210
211 use serde_json::json;
212
213 fn encode(v: &serde_json::Value) -> Vec<u8> {
215 nodedb_types::json_msgpack::json_to_msgpack(v).expect("encode")
216 }
217
218 #[test]
219 fn read_f64_fixint() {
220 assert_eq!(read_f64(&[42u8], 0), Some(42.0));
221 }
222
223 #[test]
224 fn read_f64_negative_fixint() {
225 assert_eq!(read_f64(&[0xffu8], 0), Some(-1.0));
226 }
227
228 #[test]
229 fn read_f64_float64() {
230 let buf = encode(&json!(std::f64::consts::PI));
231 assert_eq!(read_f64(&buf, 0), Some(std::f64::consts::PI));
232 }
233
234 #[test]
235 fn read_f64_uint16() {
236 let buf = encode(&json!(1000));
237 assert_eq!(read_f64(&buf, 0), Some(1000.0));
238 }
239
240 #[test]
241 fn read_f64_float32() {
242 let buf = [0xca, 0x3f, 0xc0, 0x00, 0x00];
245 let val = read_f64(&buf, 0).unwrap();
246 assert!((val - 1.5).abs() < 1e-6);
247 }
248
249 #[test]
250 fn read_i64_values() {
251 assert_eq!(read_i64(&[42u8], 0), Some(42));
252 assert_eq!(read_i64(&[0xffu8], 0), Some(-1));
253
254 let buf = encode(&json!(300));
255 assert_eq!(read_i64(&buf, 0), Some(300));
256
257 let buf = encode(&json!(-500));
258 assert_eq!(read_i64(&buf, 0), Some(-500));
259 }
260
261 #[test]
262 fn uint64_above_i64_max_never_wraps() {
263 let mut buf = vec![UINT64];
264 buf.extend_from_slice(&u64::MAX.to_be_bytes());
265 assert_eq!(read_i64(&buf, 0), None);
266 assert_eq!(read_integer(&buf, 0), Some(i128::from(u64::MAX)));
267
268 let mut edge = vec![UINT64];
269 edge.extend_from_slice(&(i64::MAX as u64).to_be_bytes());
270 assert_eq!(read_i64(&edge, 0), Some(i64::MAX));
271
272 let mut neg = vec![INT64];
273 neg.extend_from_slice(&i64::MIN.to_be_bytes());
274 assert_eq!(read_i64(&neg, 0), Some(i64::MIN));
275 assert_eq!(read_integer(&neg, 0), Some(i128::from(i64::MIN)));
276 }
277
278 #[test]
279 fn read_numeric_keeps_integers_exact() {
280 use crate::numeric_cmp::Numeric;
281 let buf = encode(&json!(9_007_199_254_740_993_i64));
282 assert!(matches!(
283 read_numeric(&buf, 0),
284 Some(Numeric::Int(9_007_199_254_740_993))
285 ));
286 let buf = encode(&json!(1.5));
287 assert!(matches!(read_numeric(&buf, 0), Some(Numeric::Float(f)) if f == 1.5));
288 let buf = encode(&json!("1"));
289 assert!(read_numeric(&buf, 0).is_none());
290 assert!(read_integer(&buf, 0).is_none());
291 }
292
293 #[test]
294 fn read_str_fixstr() {
295 let buf = encode(&json!("hi"));
296 assert_eq!(read_str(&buf, 0), Some("hi"));
297 }
298
299 #[test]
300 fn read_str_str8() {
301 let long = "a".repeat(40);
302 let buf = encode(&json!(long));
303 assert_eq!(read_str(&buf, 0), Some(long.as_str()));
304 }
305
306 #[test]
307 fn read_bool_values() {
308 assert_eq!(read_bool(&[TRUE], 0), Some(true));
309 assert_eq!(read_bool(&[FALSE], 0), Some(false));
310 assert_eq!(read_bool(&[NIL], 0), None);
311 }
312
313 #[test]
314 fn read_null_check() {
315 assert!(read_null(&[NIL], 0));
316 assert!(!read_null(&[TRUE], 0));
317 }
318
319 #[test]
320 fn map_header_fixmap() {
321 let buf = encode(&json!({"x": 1}));
322 let (count, _data_offset) = map_header(&buf, 0).unwrap();
323 assert_eq!(count, 1);
324 }
325
326 #[test]
327 fn array_header_fixarray() {
328 let buf = encode(&json!([10, 20, 30]));
329 let (count, data_offset) = array_header(&buf, 0).unwrap();
330 assert_eq!(count, 3);
331 assert_eq!(read_i64(&buf, data_offset), Some(10));
332 }
333
334 #[test]
335 fn canonical_integer_smallest_representation() {
336 let buf = encode(&json!(42));
338 assert_eq!(buf.len(), 1);
339 assert_eq!(buf[0], 42);
340
341 let buf = encode(&json!(0));
343 assert_eq!(buf.len(), 1);
344 assert_eq!(buf[0], 0);
345
346 let buf = encode(&json!(127));
348 assert_eq!(buf.len(), 1);
349 assert_eq!(buf[0], 127);
350
351 let buf = encode(&json!(128));
354 assert_eq!(buf[0], 0xd1); assert_eq!(buf.len(), 3); let buf = encode(&json!(-1));
359 assert_eq!(buf.len(), 1);
360 assert_eq!(buf[0], 0xff); let buf = encode(&json!(-32));
363 assert_eq!(buf.len(), 1);
364 assert_eq!(buf[0], 0xe0); }
366
367 #[test]
368 fn canonical_map_keys_sorted() {
369 let buf = encode(&json!({"z": 1, "a": 2, "m": 3}));
372
373 let (count, mut pos) = map_header(&buf, 0).unwrap();
375 assert_eq!(count, 3);
376
377 let mut keys = Vec::new();
378 for _ in 0..count {
379 let key = read_str(&buf, pos).unwrap();
380 keys.push(key.to_string());
381 pos = skip_value(&buf, pos).unwrap(); pos = skip_value(&buf, pos).unwrap(); }
384 assert_eq!(keys, vec!["a", "m", "z"]);
385 }
386
387 #[test]
388 fn canonical_deterministic_bytes() {
389 let doc1 = encode(&json!({"name": "alice", "age": 30, "active": true}));
391 let doc2 = encode(&json!({"age": 30, "active": true, "name": "alice"}));
392 assert_eq!(
393 doc1, doc2,
394 "same logical doc must produce identical msgpack bytes"
395 );
396 }
397
398 #[test]
399 fn canonical_nested_map_keys_sorted() {
400 let buf = encode(&json!({"outer": {"z": 1, "a": 2}}));
401 let (start, _end) = crate::msgpack_scan::field::extract_field(&buf, 0, "outer").unwrap();
403
404 let (count, mut pos) = map_header(&buf, start).unwrap();
405 assert_eq!(count, 2);
406
407 let key1 = read_str(&buf, pos).unwrap();
408 pos = skip_value(&buf, pos).unwrap();
409 pos = skip_value(&buf, pos).unwrap();
410 let key2 = read_str(&buf, pos).unwrap();
411
412 assert_eq!(key1, "a");
413 assert_eq!(key2, "z");
414 }
415
416 #[test]
417 fn read_bin_advance_all_widths() {
418 let mut off = 0;
420 let buf = [BIN8, 3, 0xde, 0xad, 0xbe, 0xff];
421 assert_eq!(
422 read_bin_advance(&buf, &mut off),
423 Some(&[0xde, 0xad, 0xbe][..])
424 );
425 assert_eq!(off, 5);
426
427 let mut off = 0;
429 let buf = [BIN16, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04];
430 assert_eq!(
431 read_bin_advance(&buf, &mut off),
432 Some(&[0x01, 0x02, 0x03, 0x04][..])
433 );
434 assert_eq!(off, 7);
435
436 let mut off = 0;
438 let buf = [BIN32, 0x00, 0x00, 0x00, 0x02, 0xaa, 0xbb];
439 assert_eq!(read_bin_advance(&buf, &mut off), Some(&[0xaa, 0xbb][..]));
440 assert_eq!(off, 7);
441
442 let mut off = 0;
444 let buf = [0xc0u8]; assert_eq!(read_bin_advance(&buf, &mut off), None);
446 assert_eq!(off, 0);
447
448 let mut off = 0;
450 let buf = [BIN8, 5, 0x01]; assert_eq!(read_bin_advance(&buf, &mut off), None);
452 }
453
454 #[test]
455 fn read_u32_advance_all_widths() {
456 let mut off = 0;
458 assert_eq!(read_u32_advance(&[42u8], &mut off), Some(42));
459 assert_eq!(off, 1);
460
461 let mut off = 0;
463 assert_eq!(read_u32_advance(&[UINT8, 200], &mut off), Some(200));
464 assert_eq!(off, 2);
465
466 let mut off = 0;
468 let buf = [UINT16, 0x12, 0x34];
469 assert_eq!(read_u32_advance(&buf, &mut off), Some(0x1234));
470 assert_eq!(off, 3);
471
472 let mut off = 0;
474 let buf = [UINT32, 0xde, 0xad, 0xbe, 0xef];
475 assert_eq!(read_u32_advance(&buf, &mut off), Some(0xdeadbeef));
476 assert_eq!(off, 5);
477
478 let mut off = 0;
480 assert_eq!(read_u32_advance(&[0xffu8], &mut off), None); assert_eq!(off, 0);
482 let mut off = 0;
483 assert_eq!(read_u32_advance(&[INT8, 5], &mut off), None);
484 let mut off = 0;
485 assert_eq!(
486 read_u32_advance(&[UINT64, 0, 0, 0, 0, 0, 0, 0, 1], &mut off),
487 None
488 );
489
490 let mut off = 0;
492 assert_eq!(read_u32_advance(&[UINT16, 0x12], &mut off), None);
493 }
494
495 #[test]
496 fn read_str_advance_basic() {
497 let mut off = 0;
499 let buf = encode(&json!("hi"));
500 assert_eq!(read_str_advance(&buf, &mut off), Some("hi"));
501 assert_eq!(off, buf.len());
502
503 let buf = encode(&json!(["one", "two"]));
505 let (count, mut off) = array_header(&buf, 0).unwrap();
506 assert_eq!(count, 2);
507 assert_eq!(read_str_advance(&buf, &mut off), Some("one"));
508 assert_eq!(read_str_advance(&buf, &mut off), Some("two"));
509 assert_eq!(off, buf.len());
510
511 let mut off = 0;
513 assert_eq!(read_str_advance(&[NIL], &mut off), None);
514 assert_eq!(off, 0);
515 }
516}