Skip to main content

rns_core/
msgpack.rs

1//! Minimal msgpack encoder/decoder for Resource advertisements and HMU packets.
2//!
3//! Supports the subset needed by Reticulum's Resource protocol:
4//! - Nil, Bool, positive/negative fixint, uint8-64, int8-32
5//! - fixstr, str8
6//! - bin8, bin16, bin32
7//! - fixarray, array16
8//! - fixmap, map16
9
10use alloc::string::String;
11use alloc::vec::Vec;
12use core::fmt;
13
14/// A msgpack value.
15#[derive(Debug, Clone)]
16pub enum Value {
17    Nil,
18    Bool(bool),
19    UInt(u64),
20    Int(i64),
21    Float(f64),
22    Bin(Vec<u8>),
23    Str(String),
24    Array(Vec<Value>),
25    Map(Vec<(Value, Value)>),
26}
27
28impl PartialEq for Value {
29    fn eq(&self, other: &Self) -> bool {
30        match (self, other) {
31            (Value::Nil, Value::Nil) => true,
32            (Value::Bool(a), Value::Bool(b)) => a == b,
33            (Value::UInt(a), Value::UInt(b)) => a == b,
34            (Value::Int(a), Value::Int(b)) => a == b,
35            (Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
36            (Value::Bin(a), Value::Bin(b)) => a == b,
37            (Value::Str(a), Value::Str(b)) => a == b,
38            (Value::Array(a), Value::Array(b)) => a == b,
39            (Value::Map(a), Value::Map(b)) => a == b,
40            _ => false,
41        }
42    }
43}
44
45impl Value {
46    /// Get as u64 if this is a UInt.
47    pub fn as_uint(&self) -> Option<u64> {
48        match self {
49            Value::UInt(v) => Some(*v),
50            _ => None,
51        }
52    }
53
54    /// Get as i64 if this is an Int.
55    pub fn as_int(&self) -> Option<i64> {
56        match self {
57            Value::Int(v) => Some(*v),
58            _ => None,
59        }
60    }
61
62    /// Get as integer (works for both UInt and Int).
63    pub fn as_integer(&self) -> Option<i64> {
64        match self {
65            Value::UInt(v) => {
66                if *v <= i64::MAX as u64 {
67                    Some(*v as i64)
68                } else {
69                    None
70                }
71            }
72            Value::Int(v) => Some(*v),
73            _ => None,
74        }
75    }
76
77    /// Get as bool.
78    pub fn as_bool(&self) -> Option<bool> {
79        match self {
80            Value::Bool(v) => Some(*v),
81            _ => None,
82        }
83    }
84
85    /// Get as f64 if Float.
86    pub fn as_float(&self) -> Option<f64> {
87        match self {
88            Value::Float(v) => Some(*v),
89            _ => None,
90        }
91    }
92
93    /// Get as f64, accepting Float, UInt, or Int.
94    pub fn as_number(&self) -> Option<f64> {
95        match self {
96            Value::Float(v) => Some(*v),
97            Value::UInt(v) => Some(*v as f64),
98            Value::Int(v) => Some(*v as f64),
99            _ => None,
100        }
101    }
102
103    /// Get as byte slice if Bin.
104    pub fn as_bin(&self) -> Option<&[u8]> {
105        match self {
106            Value::Bin(v) => Some(v),
107            _ => None,
108        }
109    }
110
111    /// Get as string slice if Str.
112    pub fn as_str(&self) -> Option<&str> {
113        match self {
114            Value::Str(v) => Some(v),
115            _ => None,
116        }
117    }
118
119    /// Get as array slice.
120    pub fn as_array(&self) -> Option<&[Value]> {
121        match self {
122            Value::Array(v) => Some(v),
123            _ => None,
124        }
125    }
126
127    /// Get as map slice.
128    pub fn as_map(&self) -> Option<&[(Value, Value)]> {
129        match self {
130            Value::Map(v) => Some(v),
131            _ => None,
132        }
133    }
134
135    /// Check if nil.
136    pub fn is_nil(&self) -> bool {
137        matches!(self, Value::Nil)
138    }
139
140    /// Look up a string key in a map.
141    pub fn map_get(&self, key: &str) -> Option<&Value> {
142        self.as_map().and_then(|entries| {
143            entries.iter().find_map(|(k, v)| {
144                if let Value::Str(s) = k {
145                    if s == key {
146                        return Some(v);
147                    }
148                }
149                None
150            })
151        })
152    }
153}
154
155/// Maximum nesting depth for msgpack decoding.
156const MAX_DEPTH: usize = 32;
157
158/// Msgpack error.
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub enum Error {
161    UnexpectedEof,
162    UnsupportedFormat(u8),
163    InvalidUtf8,
164    TrailingData,
165    MaxDepthExceeded,
166}
167
168impl fmt::Display for Error {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        match self {
171            Error::UnexpectedEof => write!(f, "Unexpected end of msgpack data"),
172            Error::UnsupportedFormat(b) => write!(f, "Unsupported msgpack format: 0x{:02x}", b),
173            Error::InvalidUtf8 => write!(f, "Invalid UTF-8 in msgpack string"),
174            Error::TrailingData => write!(f, "Trailing data after msgpack value"),
175            Error::MaxDepthExceeded => write!(f, "Maximum nesting depth exceeded"),
176        }
177    }
178}
179
180// ============================================================================
181// Encoder
182// ============================================================================
183
184/// Encode a Value to msgpack bytes.
185pub fn pack(value: &Value) -> Vec<u8> {
186    let mut buf = Vec::new();
187    pack_into(value, &mut buf);
188    buf
189}
190
191fn pack_into(value: &Value, buf: &mut Vec<u8>) {
192    match value {
193        Value::Nil => buf.push(0xc0),
194        Value::Bool(true) => buf.push(0xc3),
195        Value::Bool(false) => buf.push(0xc2),
196        Value::UInt(v) => pack_uint(*v, buf),
197        Value::Int(v) => pack_int(*v, buf),
198        Value::Float(v) => {
199            buf.push(0xcb);
200            buf.extend_from_slice(&v.to_bits().to_be_bytes());
201        }
202        Value::Bin(data) => pack_bin(data, buf),
203        Value::Str(s) => pack_str(s, buf),
204        Value::Array(items) => pack_array(items, buf),
205        Value::Map(entries) => pack_map(entries, buf),
206    }
207}
208
209fn pack_uint(v: u64, buf: &mut Vec<u8>) {
210    if v <= 127 {
211        buf.push(v as u8);
212    } else if v <= 0xFF {
213        buf.push(0xcc);
214        buf.push(v as u8);
215    } else if v <= 0xFFFF {
216        buf.push(0xcd);
217        buf.extend_from_slice(&(v as u16).to_be_bytes());
218    } else if v <= 0xFFFF_FFFF {
219        buf.push(0xce);
220        buf.extend_from_slice(&(v as u32).to_be_bytes());
221    } else {
222        buf.push(0xcf);
223        buf.extend_from_slice(&v.to_be_bytes());
224    }
225}
226
227fn pack_int(v: i64, buf: &mut Vec<u8>) {
228    if v >= 0 {
229        pack_uint(v as u64, buf);
230    } else if v >= -32 {
231        buf.push(v as u8); // negative fixint: 0xe0..0xff
232    } else if v >= -128 {
233        buf.push(0xd0);
234        buf.push(v as i8 as u8);
235    } else if v >= -32768 {
236        buf.push(0xd1);
237        buf.extend_from_slice(&(v as i16).to_be_bytes());
238    } else if v >= -2_147_483_648 {
239        buf.push(0xd2);
240        buf.extend_from_slice(&(v as i32).to_be_bytes());
241    } else {
242        buf.push(0xd3);
243        buf.extend_from_slice(&v.to_be_bytes());
244    }
245}
246
247fn pack_bin(data: &[u8], buf: &mut Vec<u8>) {
248    let len = data.len();
249    if len <= 0xFF {
250        buf.push(0xc4);
251        buf.push(len as u8);
252    } else if len <= 0xFFFF {
253        buf.push(0xc5);
254        buf.extend_from_slice(&(len as u16).to_be_bytes());
255    } else {
256        buf.push(0xc6);
257        buf.extend_from_slice(&(len as u32).to_be_bytes());
258    }
259    buf.extend_from_slice(data);
260}
261
262fn pack_str(s: &str, buf: &mut Vec<u8>) {
263    let bytes = s.as_bytes();
264    let len = bytes.len();
265    if len <= 31 {
266        buf.push(0xa0 | len as u8);
267    } else if len <= 0xFF {
268        buf.push(0xd9);
269        buf.push(len as u8);
270    } else if len <= 0xFFFF {
271        buf.push(0xda);
272        buf.extend_from_slice(&(len as u16).to_be_bytes());
273    } else {
274        buf.push(0xdb);
275        buf.extend_from_slice(&(len as u32).to_be_bytes());
276    }
277    buf.extend_from_slice(bytes);
278}
279
280fn pack_array(items: &[Value], buf: &mut Vec<u8>) {
281    let len = items.len();
282    if len <= 15 {
283        buf.push(0x90 | len as u8);
284    } else if len <= 0xFFFF {
285        buf.push(0xdc);
286        buf.extend_from_slice(&(len as u16).to_be_bytes());
287    } else {
288        buf.push(0xdd);
289        buf.extend_from_slice(&(len as u32).to_be_bytes());
290    }
291    for item in items {
292        pack_into(item, buf);
293    }
294}
295
296fn pack_map(entries: &[(Value, Value)], buf: &mut Vec<u8>) {
297    let len = entries.len();
298    if len <= 15 {
299        buf.push(0x80 | len as u8);
300    } else if len <= 0xFFFF {
301        buf.push(0xde);
302        buf.extend_from_slice(&(len as u16).to_be_bytes());
303    } else {
304        buf.push(0xdf);
305        buf.extend_from_slice(&(len as u32).to_be_bytes());
306    }
307    for (k, v) in entries {
308        pack_into(k, buf);
309        pack_into(v, buf);
310    }
311}
312
313/// Convenience: pack a map from string keys.
314pub fn pack_str_map(entries: &[(&str, Value)]) -> Vec<u8> {
315    let map: Vec<(Value, Value)> = entries
316        .iter()
317        .map(|(k, v)| (Value::Str(String::from(*k)), v.clone()))
318        .collect();
319    pack(&Value::Map(map))
320}
321
322// ============================================================================
323// Decoder
324// ============================================================================
325
326/// Decode a single msgpack value from the start of `data`.
327/// Returns (value, bytes_consumed).
328pub fn unpack(data: &[u8]) -> Result<(Value, usize), Error> {
329    unpack_depth(data, 0)
330}
331
332fn unpack_depth(data: &[u8], depth: usize) -> Result<(Value, usize), Error> {
333    if data.is_empty() {
334        return Err(Error::UnexpectedEof);
335    }
336    if depth > MAX_DEPTH {
337        return Err(Error::MaxDepthExceeded);
338    }
339    let b = data[0];
340    match b {
341        // positive fixint: 0x00..0x7f
342        0x00..=0x7f => Ok((Value::UInt(b as u64), 1)),
343
344        // fixmap: 0x80..0x8f
345        0x80..=0x8f => {
346            let len = (b & 0x0f) as usize;
347            unpack_map_entries(data, 1, len, depth)
348        }
349
350        // fixarray: 0x90..0x9f
351        0x90..=0x9f => {
352            let len = (b & 0x0f) as usize;
353            unpack_array_entries(data, 1, len, depth)
354        }
355
356        // fixstr: 0xa0..0xbf
357        0xa0..=0xbf => {
358            let len = (b & 0x1f) as usize;
359            unpack_str_bytes(data, 1, len)
360        }
361
362        // nil
363        0xc0 => Ok((Value::Nil, 1)),
364
365        // (unused)
366        0xc1 => Err(Error::UnsupportedFormat(b)),
367
368        // bool
369        0xc2 => Ok((Value::Bool(false), 1)),
370        0xc3 => Ok((Value::Bool(true), 1)),
371
372        // float32
373        0xca => {
374            ensure_len(data, 5)?;
375            let bits = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
376            Ok((Value::Float(f32::from_bits(bits) as f64), 5))
377        }
378
379        // float64
380        0xcb => {
381            ensure_len(data, 9)?;
382            let bits = u64::from_be_bytes([
383                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
384            ]);
385            Ok((Value::Float(f64::from_bits(bits)), 9))
386        }
387
388        // bin8
389        0xc4 => {
390            ensure_len(data, 2)?;
391            let len = data[1] as usize;
392            let needed = 2usize.checked_add(len).ok_or(Error::UnexpectedEof)?;
393            ensure_len(data, needed)?;
394            Ok((Value::Bin(data[2..2 + len].to_vec()), 2 + len))
395        }
396
397        // bin16
398        0xc5 => {
399            ensure_len(data, 3)?;
400            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
401            let needed = 3usize.checked_add(len).ok_or(Error::UnexpectedEof)?;
402            ensure_len(data, needed)?;
403            Ok((Value::Bin(data[3..3 + len].to_vec()), 3 + len))
404        }
405
406        // bin32
407        0xc6 => {
408            ensure_len(data, 5)?;
409            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
410            let needed = 5usize.checked_add(len).ok_or(Error::UnexpectedEof)?;
411            ensure_len(data, needed)?;
412            Ok((Value::Bin(data[5..5 + len].to_vec()), 5 + len))
413        }
414
415        // uint8
416        0xcc => {
417            ensure_len(data, 2)?;
418            Ok((Value::UInt(data[1] as u64), 2))
419        }
420
421        // uint16
422        0xcd => {
423            ensure_len(data, 3)?;
424            let v = u16::from_be_bytes([data[1], data[2]]);
425            Ok((Value::UInt(v as u64), 3))
426        }
427
428        // uint32
429        0xce => {
430            ensure_len(data, 5)?;
431            let v = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
432            Ok((Value::UInt(v as u64), 5))
433        }
434
435        // uint64
436        0xcf => {
437            ensure_len(data, 9)?;
438            let v = u64::from_be_bytes([
439                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
440            ]);
441            Ok((Value::UInt(v), 9))
442        }
443
444        // int8
445        0xd0 => {
446            ensure_len(data, 2)?;
447            Ok((Value::Int(data[1] as i8 as i64), 2))
448        }
449
450        // int16
451        0xd1 => {
452            ensure_len(data, 3)?;
453            let v = i16::from_be_bytes([data[1], data[2]]);
454            Ok((Value::Int(v as i64), 3))
455        }
456
457        // int32
458        0xd2 => {
459            ensure_len(data, 5)?;
460            let v = i32::from_be_bytes([data[1], data[2], data[3], data[4]]);
461            Ok((Value::Int(v as i64), 5))
462        }
463
464        // int64
465        0xd3 => {
466            ensure_len(data, 9)?;
467            let v = i64::from_be_bytes([
468                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
469            ]);
470            Ok((Value::Int(v), 9))
471        }
472
473        // str8
474        0xd9 => {
475            ensure_len(data, 2)?;
476            let len = data[1] as usize;
477            unpack_str_bytes(data, 2, len)
478        }
479
480        // str16
481        0xda => {
482            ensure_len(data, 3)?;
483            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
484            unpack_str_bytes(data, 3, len)
485        }
486
487        // str32
488        0xdb => {
489            ensure_len(data, 5)?;
490            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
491            unpack_str_bytes(data, 5, len)
492        }
493
494        // array16
495        0xdc => {
496            ensure_len(data, 3)?;
497            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
498            unpack_array_entries(data, 3, len, depth)
499        }
500
501        // array32
502        0xdd => {
503            ensure_len(data, 5)?;
504            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
505            unpack_array_entries(data, 5, len, depth)
506        }
507
508        // map16
509        0xde => {
510            ensure_len(data, 3)?;
511            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
512            unpack_map_entries(data, 3, len, depth)
513        }
514
515        // map32
516        0xdf => {
517            ensure_len(data, 5)?;
518            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
519            unpack_map_entries(data, 5, len, depth)
520        }
521
522        // negative fixint: 0xe0..0xff
523        0xe0..=0xff => Ok((Value::Int(b as i8 as i64), 1)),
524
525        _ => Err(Error::UnsupportedFormat(b)),
526    }
527}
528
529/// Decode a complete msgpack value, ensuring no trailing data.
530pub fn unpack_exact(data: &[u8]) -> Result<Value, Error> {
531    let (value, consumed) = unpack(data)?;
532    if consumed != data.len() {
533        return Err(Error::TrailingData);
534    }
535    Ok(value)
536}
537
538fn ensure_len(data: &[u8], needed: usize) -> Result<(), Error> {
539    if data.len() < needed {
540        Err(Error::UnexpectedEof)
541    } else {
542        Ok(())
543    }
544}
545
546fn unpack_str_bytes(data: &[u8], offset: usize, len: usize) -> Result<(Value, usize), Error> {
547    let needed = offset.checked_add(len).ok_or(Error::UnexpectedEof)?;
548    ensure_len(data, needed)?;
549    let bytes = &data[offset..offset + len];
550    let s = core::str::from_utf8(bytes).map_err(|_| Error::InvalidUtf8)?;
551    Ok((Value::Str(String::from(s)), offset + len))
552}
553
554fn unpack_array_entries(
555    data: &[u8],
556    start: usize,
557    count: usize,
558    depth: usize,
559) -> Result<(Value, usize), Error> {
560    if count > data.len().saturating_sub(start) {
561        return Err(Error::UnexpectedEof);
562    }
563    let mut offset = start;
564    let mut items = Vec::with_capacity(count);
565    for _ in 0..count {
566        let (v, consumed) = unpack_depth(&data[offset..], depth + 1)?;
567        items.push(v);
568        offset += consumed;
569    }
570    Ok((Value::Array(items), offset))
571}
572
573fn unpack_map_entries(
574    data: &[u8],
575    start: usize,
576    count: usize,
577    depth: usize,
578) -> Result<(Value, usize), Error> {
579    if count
580        .checked_mul(2)
581        .is_none_or(|minimum_items| minimum_items > data.len().saturating_sub(start))
582    {
583        return Err(Error::UnexpectedEof);
584    }
585    let mut offset = start;
586    let mut entries = Vec::with_capacity(count);
587    for _ in 0..count {
588        let (k, kc) = unpack_depth(&data[offset..], depth + 1)?;
589        offset += kc;
590        let (v, vc) = unpack_depth(&data[offset..], depth + 1)?;
591        offset += vc;
592        entries.push((k, v));
593    }
594    Ok((Value::Map(entries), offset))
595}
596
597#[cfg(test)]
598mod tests {
599    use super::*;
600
601    fn roundtrip(v: &Value) -> Value {
602        let packed = pack(v);
603        let (unpacked, consumed) = unpack(&packed).unwrap();
604        assert_eq!(consumed, packed.len(), "all bytes consumed");
605        unpacked
606    }
607
608    #[test]
609    fn test_nil() {
610        let packed = pack(&Value::Nil);
611        assert_eq!(packed, vec![0xc0]);
612        assert_eq!(roundtrip(&Value::Nil), Value::Nil);
613    }
614
615    #[test]
616    fn test_bool() {
617        assert_eq!(pack(&Value::Bool(true)), vec![0xc3]);
618        assert_eq!(pack(&Value::Bool(false)), vec![0xc2]);
619        assert_eq!(roundtrip(&Value::Bool(true)), Value::Bool(true));
620        assert_eq!(roundtrip(&Value::Bool(false)), Value::Bool(false));
621    }
622
623    #[test]
624    fn test_positive_fixint() {
625        assert_eq!(pack(&Value::UInt(0)), vec![0x00]);
626        assert_eq!(pack(&Value::UInt(127)), vec![0x7f]);
627        assert_eq!(roundtrip(&Value::UInt(0)), Value::UInt(0));
628        assert_eq!(roundtrip(&Value::UInt(42)), Value::UInt(42));
629        assert_eq!(roundtrip(&Value::UInt(127)), Value::UInt(127));
630    }
631
632    #[test]
633    fn test_uint8() {
634        assert_eq!(pack(&Value::UInt(128)), vec![0xcc, 0x80]);
635        assert_eq!(pack(&Value::UInt(255)), vec![0xcc, 0xff]);
636        assert_eq!(roundtrip(&Value::UInt(128)), Value::UInt(128));
637        assert_eq!(roundtrip(&Value::UInt(255)), Value::UInt(255));
638    }
639
640    #[test]
641    fn test_uint16() {
642        assert_eq!(pack(&Value::UInt(256)), vec![0xcd, 0x01, 0x00]);
643        assert_eq!(roundtrip(&Value::UInt(256)), Value::UInt(256));
644        assert_eq!(roundtrip(&Value::UInt(0xFFFF)), Value::UInt(0xFFFF));
645    }
646
647    #[test]
648    fn test_uint32() {
649        assert_eq!(
650            pack(&Value::UInt(0x10000)),
651            vec![0xce, 0x00, 0x01, 0x00, 0x00]
652        );
653        assert_eq!(roundtrip(&Value::UInt(0x10000)), Value::UInt(0x10000));
654        assert_eq!(roundtrip(&Value::UInt(0xFFFFFFFF)), Value::UInt(0xFFFFFFFF));
655    }
656
657    #[test]
658    fn test_uint64() {
659        let big = 0x1_0000_0000u64;
660        assert_eq!(roundtrip(&Value::UInt(big)), Value::UInt(big));
661        let huge = u64::MAX;
662        assert_eq!(roundtrip(&Value::UInt(huge)), Value::UInt(huge));
663    }
664
665    #[test]
666    fn test_negative_fixint() {
667        // -1 = 0xff, -32 = 0xe0
668        assert_eq!(pack(&Value::Int(-1)), vec![0xff]);
669        assert_eq!(pack(&Value::Int(-32)), vec![0xe0]);
670        assert_eq!(roundtrip(&Value::Int(-1)), Value::Int(-1));
671        assert_eq!(roundtrip(&Value::Int(-32)), Value::Int(-32));
672    }
673
674    #[test]
675    fn test_int8() {
676        assert_eq!(pack(&Value::Int(-33)), vec![0xd0, 0xdf]);
677        assert_eq!(roundtrip(&Value::Int(-33)), Value::Int(-33));
678        assert_eq!(roundtrip(&Value::Int(-128)), Value::Int(-128));
679    }
680
681    #[test]
682    fn test_int16() {
683        assert_eq!(roundtrip(&Value::Int(-129)), Value::Int(-129));
684        assert_eq!(roundtrip(&Value::Int(-32768)), Value::Int(-32768));
685    }
686
687    #[test]
688    fn test_int32() {
689        assert_eq!(roundtrip(&Value::Int(-32769)), Value::Int(-32769));
690    }
691
692    #[test]
693    fn test_positive_int_packed_as_uint() {
694        // Positive values always encode as uint format
695        let packed = pack(&Value::Int(42));
696        assert_eq!(packed, vec![42]); // positive fixint
697    }
698
699    #[test]
700    fn test_fixstr() {
701        let v = Value::Str(String::from("t"));
702        let packed = pack(&v);
703        assert_eq!(packed[0], 0xa1); // fixstr len=1
704        assert_eq!(roundtrip(&v), v);
705
706        let v = Value::Str(String::from("hello"));
707        assert_eq!(roundtrip(&v), v);
708
709        // Empty string
710        let v = Value::Str(String::new());
711        assert_eq!(pack(&v), vec![0xa0]);
712        assert_eq!(roundtrip(&v), v);
713    }
714
715    #[test]
716    fn test_str8() {
717        let s: String = "a".repeat(32);
718        let v = Value::Str(s);
719        let packed = pack(&v);
720        assert_eq!(packed[0], 0xd9);
721        assert_eq!(packed[1], 32);
722        assert_eq!(roundtrip(&v), v);
723    }
724
725    #[test]
726    fn test_bin8() {
727        let v = Value::Bin(vec![1, 2, 3]);
728        let packed = pack(&v);
729        assert_eq!(packed[0], 0xc4);
730        assert_eq!(packed[1], 3);
731        assert_eq!(roundtrip(&v), v);
732    }
733
734    #[test]
735    fn test_bin16() {
736        let data = vec![0xAB; 300];
737        let v = Value::Bin(data);
738        let packed = pack(&v);
739        assert_eq!(packed[0], 0xc5);
740        assert_eq!(roundtrip(&v), v);
741    }
742
743    #[test]
744    fn test_bin32() {
745        // bin32 threshold is > 65535 bytes, skip actual large allocation but
746        // test the format byte by manually checking a 0-length edge
747        let data = vec![0xCD; 70000];
748        let v = Value::Bin(data);
749        let packed = pack(&v);
750        assert_eq!(packed[0], 0xc6);
751        assert_eq!(roundtrip(&v), v);
752    }
753
754    #[test]
755    fn test_fixarray() {
756        let v = Value::Array(vec![Value::UInt(1), Value::UInt(2), Value::UInt(3)]);
757        let packed = pack(&v);
758        assert_eq!(packed[0], 0x93); // fixarray len=3
759        assert_eq!(roundtrip(&v), v);
760
761        // Empty array
762        let v = Value::Array(vec![]);
763        assert_eq!(pack(&v), vec![0x90]);
764        assert_eq!(roundtrip(&v), v);
765    }
766
767    #[test]
768    fn test_fixmap() {
769        let v = Value::Map(vec![
770            (Value::Str(String::from("a")), Value::UInt(1)),
771            (Value::Str(String::from("b")), Value::UInt(2)),
772        ]);
773        let packed = pack(&v);
774        assert_eq!(packed[0], 0x82); // fixmap len=2
775        assert_eq!(roundtrip(&v), v);
776    }
777
778    #[test]
779    fn test_nested_structure() {
780        let v = Value::Map(vec![
781            (Value::Str(String::from("t")), Value::UInt(1000)),
782            (Value::Str(String::from("m")), Value::Bin(vec![0xAA; 10])),
783            (Value::Str(String::from("q")), Value::Nil),
784        ]);
785        assert_eq!(roundtrip(&v), v);
786    }
787
788    #[test]
789    fn test_pack_str_map() {
790        let packed = pack_str_map(&[("x", Value::UInt(42)), ("y", Value::Bool(true))]);
791        let (v, _) = unpack(&packed).unwrap();
792        assert_eq!(v.map_get("x").unwrap().as_uint(), Some(42));
793        assert_eq!(v.map_get("y").unwrap().as_bool(), Some(true));
794    }
795
796    #[test]
797    fn test_map_get_missing_key() {
798        let v = Value::Map(vec![(Value::Str(String::from("a")), Value::UInt(1))]);
799        assert!(v.map_get("b").is_none());
800    }
801
802    #[test]
803    fn test_hmu_array_format() {
804        // HMU format: [segment_int, hashmap_bytes]
805        let v = Value::Array(vec![
806            Value::UInt(2),
807            Value::Bin(vec![0x11, 0x22, 0x33, 0x44, 0xAA, 0xBB, 0xCC, 0xDD]),
808        ]);
809        assert_eq!(roundtrip(&v), v);
810    }
811
812    #[test]
813    fn test_decode_error_eof() {
814        assert_eq!(unpack(&[]), Err(Error::UnexpectedEof));
815        // bin8 with length but no data
816        assert_eq!(unpack(&[0xc4, 0x05]), Err(Error::UnexpectedEof));
817    }
818
819    #[test]
820    fn test_declared_array_length_cannot_force_large_allocation() {
821        let data = [0xdd, 0xff, 0xff, 0xff, 0xff];
822        assert_eq!(unpack(&data), Err(Error::UnexpectedEof));
823    }
824
825    #[test]
826    fn test_declared_map_length_cannot_force_large_allocation() {
827        let data = [0xdf, 0x7f, 0xff, 0xff, 0xff];
828        assert_eq!(unpack(&data), Err(Error::UnexpectedEof));
829    }
830
831    #[test]
832    fn test_unpack_exact_trailing() {
833        let packed = pack(&Value::UInt(42));
834        let mut with_extra = packed.clone();
835        with_extra.push(0x00);
836        assert!(unpack_exact(&with_extra).is_err());
837        assert!(unpack_exact(&packed).is_ok());
838    }
839
840    #[test]
841    fn test_value_accessors() {
842        assert_eq!(Value::UInt(42).as_uint(), Some(42));
843        assert_eq!(Value::UInt(42).as_int(), None);
844        assert_eq!(Value::UInt(42).as_integer(), Some(42));
845        assert_eq!(Value::Int(-5).as_integer(), Some(-5));
846        assert_eq!(Value::Bool(true).as_bool(), Some(true));
847        assert_eq!(Value::Bin(vec![1]).as_bin(), Some(&[1u8][..]));
848        assert_eq!(Value::Str(String::from("x")).as_str(), Some("x"));
849        assert!(Value::Nil.is_nil());
850    }
851
852    #[test]
853    fn test_max_depth_exceeded() {
854        // Build deeply nested arrays: [[[[...]]]] beyond MAX_DEPTH
855        let mut data = Vec::new();
856        data.extend(core::iter::repeat_n(0x91, MAX_DEPTH + 2)); // fixarray of length 1
857        data.push(0x01); // innermost value: uint 1
858        assert_eq!(unpack(&data), Err(Error::MaxDepthExceeded));
859    }
860
861    #[test]
862    fn test_depth_within_limit() {
863        // Build nested arrays within limit (depth 5)
864        let mut data = Vec::new();
865        data.extend(core::iter::repeat_n(0x91, 5)); // fixarray of length 1
866        data.push(0x01); // innermost value
867        let (val, _) = unpack(&data).unwrap();
868        // Should be Array([Array([Array([Array([Array([UInt(1)])])])])])
869        let mut current = &val;
870        for _ in 0..5 {
871            current = &current.as_array().unwrap()[0];
872        }
873        assert_eq!(current.as_uint(), Some(1));
874    }
875
876    #[test]
877    fn test_int64_roundtrip() {
878        let v = Value::Int(i64::MIN);
879        assert_eq!(roundtrip(&v), v);
880        let v = Value::Int(-2_147_483_649); // beyond i32 range
881        assert_eq!(roundtrip(&v), v);
882    }
883
884    #[test]
885    fn test_str16_roundtrip() {
886        let s: String = "x".repeat(256);
887        let v = Value::Str(s);
888        let packed = pack(&v);
889        assert_eq!(packed[0], 0xda); // str16
890        assert_eq!(roundtrip(&v), v);
891    }
892
893    #[test]
894    fn test_array16_roundtrip() {
895        let items: Vec<Value> = (0..16).map(Value::UInt).collect();
896        let v = Value::Array(items);
897        let packed = pack(&v);
898        assert_eq!(packed[0], 0xdc); // array16
899        assert_eq!(roundtrip(&v), v);
900    }
901
902    #[test]
903    fn test_map16_roundtrip() {
904        let entries: Vec<(Value, Value)> = (0..16)
905            .map(|i| (Value::UInt(i), Value::Bool(i % 2 == 0)))
906            .collect();
907        let v = Value::Map(entries);
908        let packed = pack(&v);
909        assert_eq!(packed[0], 0xde); // map16
910        assert_eq!(roundtrip(&v), v);
911    }
912
913    #[test]
914    fn test_unsupported_format() {
915        // 0xc1 is unused/never valid
916        assert_eq!(unpack(&[0xc1]), Err(Error::UnsupportedFormat(0xc1)));
917    }
918}