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
209pub(crate) fn 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
247pub(crate) fn 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
262pub(crate) fn 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
280/// Append the header of an array of `len` items, as [`pack`] writes it.
281pub fn pack_array_header(len: usize, buf: &mut Vec<u8>) {
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}
292
293fn pack_map_header(len: usize, buf: &mut Vec<u8>) {
294    if len <= 15 {
295        buf.push(0x80 | len as u8);
296    } else if len <= 0xFFFF {
297        buf.push(0xde);
298        buf.extend_from_slice(&(len as u16).to_be_bytes());
299    } else {
300        buf.push(0xdf);
301        buf.extend_from_slice(&(len as u32).to_be_bytes());
302    }
303}
304
305/// Append binary data, as [`pack`] writes [`Value::Bin`].
306pub fn pack_bin_into(data: &[u8], buf: &mut Vec<u8>) {
307    pack_bin(data, buf);
308}
309
310/// Append a value decoded by [`unpack_ref`] exactly as [`pack`] writes the
311/// [`Value`] that [`unpack`] decodes from the same bytes.
312pub fn pack_ref_into(value: ValueRef<'_>, buf: &mut Vec<u8>) {
313    match value {
314        ValueRef::Nil => buf.push(0xc0),
315        ValueRef::Bool(true) => buf.push(0xc3),
316        ValueRef::Bool(false) => buf.push(0xc2),
317        ValueRef::UInt(v) => pack_uint(v, buf),
318        ValueRef::Int(v) => pack_int(v, buf),
319        ValueRef::Float(v) => {
320            buf.push(0xcb);
321            buf.extend_from_slice(&v.to_bits().to_be_bytes());
322        }
323        ValueRef::Bin(data) => pack_bin(data, buf),
324        ValueRef::Str(s) => pack_str(s, buf),
325        ValueRef::Array { len, .. } => {
326            pack_array_header(len, buf);
327            for item in value.array_items().into_iter().flatten() {
328                pack_ref_into(item, buf);
329            }
330        }
331        ValueRef::Map { len, .. } => {
332            pack_map_header(len, buf);
333            for (k, v) in value.map_entries().into_iter().flatten() {
334                pack_ref_into(k, buf);
335                pack_ref_into(v, buf);
336            }
337        }
338    }
339}
340
341fn pack_array(items: &[Value], buf: &mut Vec<u8>) {
342    pack_array_header(items.len(), buf);
343    for item in items {
344        pack_into(item, buf);
345    }
346}
347
348fn pack_map(entries: &[(Value, Value)], buf: &mut Vec<u8>) {
349    pack_map_header(entries.len(), buf);
350    for (k, v) in entries {
351        pack_into(k, buf);
352        pack_into(v, buf);
353    }
354}
355
356/// Convenience: pack a map from string keys.
357pub fn pack_str_map(entries: &[(&str, Value)]) -> Vec<u8> {
358    let map: Vec<(Value, Value)> = entries
359        .iter()
360        .map(|(k, v)| (Value::Str(String::from(*k)), v.clone()))
361        .collect();
362    pack(&Value::Map(map))
363}
364
365// ============================================================================
366// Decoder
367// ============================================================================
368
369/// Decode a single msgpack value from the start of `data`.
370/// Returns (value, bytes_consumed).
371pub fn unpack(data: &[u8]) -> Result<(Value, usize), Error> {
372    unpack_depth(data, 0)
373}
374
375fn unpack_depth(data: &[u8], depth: usize) -> Result<(Value, usize), Error> {
376    let (value, consumed) = unpack_ref(data, depth)?;
377    Ok((value.to_owned_value()?, consumed))
378}
379
380/// Decode a complete msgpack value, ensuring no trailing data.
381pub fn unpack_exact(data: &[u8]) -> Result<Value, Error> {
382    let (value, consumed) = unpack(data)?;
383    if consumed != data.len() {
384        return Err(Error::TrailingData);
385    }
386    Ok(value)
387}
388
389/// Decode a complete msgpack value without copying it, ensuring no trailing
390/// data. Accepts and rejects exactly the inputs [`unpack_exact`] does.
391pub fn unpack_exact_ref(data: &[u8]) -> Result<ValueRef<'_>, Error> {
392    let (value, consumed) = unpack_ref(data, 0)?;
393    if consumed != data.len() {
394        return Err(Error::TrailingData);
395    }
396    Ok(value)
397}
398
399fn ensure_len(data: &[u8], needed: usize) -> Result<(), Error> {
400    if data.len() < needed {
401        Err(Error::UnexpectedEof)
402    } else {
403        Ok(())
404    }
405}
406
407/// A decoded msgpack value borrowing from its input. Arrays and maps are
408/// validated when decoded (formats, nesting depth, UTF-8) and keep their
409/// encoded items, which [`ValueRef::array_items`] and [`ValueRef::map_entries`]
410/// decode on demand.
411#[derive(Debug, Clone, Copy, PartialEq)]
412pub enum ValueRef<'a> {
413    Nil,
414    Bool(bool),
415    UInt(u64),
416    Int(i64),
417    Float(f64),
418    Bin(&'a [u8]),
419    Str(&'a str),
420    Array {
421        len: usize,
422        items: &'a [u8],
423        depth: usize,
424    },
425    Map {
426        len: usize,
427        entries: &'a [u8],
428        depth: usize,
429    },
430}
431
432impl<'a> ValueRef<'a> {
433    pub fn as_uint(&self) -> Option<u64> {
434        match self {
435            ValueRef::UInt(v) => Some(*v),
436            _ => None,
437        }
438    }
439
440    pub fn as_bin(&self) -> Option<&'a [u8]> {
441        match self {
442            ValueRef::Bin(v) => Some(v),
443            _ => None,
444        }
445    }
446
447    pub fn as_str(&self) -> Option<&'a str> {
448        match self {
449            ValueRef::Str(v) => Some(v),
450            _ => None,
451        }
452    }
453
454    pub fn is_nil(&self) -> bool {
455        matches!(self, ValueRef::Nil)
456    }
457
458    /// The items of an array, or `None` for any other value.
459    pub fn array_items(&self) -> Option<Items<'a>> {
460        match *self {
461            ValueRef::Array { len, items, depth } => Some(Items {
462                rest: items,
463                remaining: len,
464                depth: depth + 1,
465            }),
466            _ => None,
467        }
468    }
469
470    /// The (key, value) entries of a map, or `None` for any other value.
471    pub fn map_entries(&self) -> Option<Entries<'a>> {
472        match *self {
473            ValueRef::Map {
474                len,
475                entries,
476                depth,
477            } => Some(Entries(Items {
478                rest: entries,
479                remaining: len * 2,
480                depth: depth + 1,
481            })),
482            _ => None,
483        }
484    }
485
486    /// Look up a string key in a map: the first entry with that key, as
487    /// [`Value::map_get`] does.
488    pub fn map_get(&self, key: &str) -> Option<ValueRef<'a>> {
489        self.map_entries()?
490            .find_map(|(k, v)| (k.as_str() == Some(key)).then_some(v))
491    }
492
493    fn to_owned_value(self) -> Result<Value, Error> {
494        Ok(match self {
495            ValueRef::Nil => Value::Nil,
496            ValueRef::Bool(b) => Value::Bool(b),
497            ValueRef::UInt(v) => Value::UInt(v),
498            ValueRef::Int(v) => Value::Int(v),
499            ValueRef::Float(v) => Value::Float(v),
500            ValueRef::Bin(b) => Value::Bin(b.to_vec()),
501            ValueRef::Str(s) => Value::Str(String::from(s)),
502            ValueRef::Array { len, .. } => {
503                let mut items = Vec::with_capacity(len);
504                for item in self.array_items().into_iter().flatten() {
505                    items.push(item.to_owned_value()?);
506                }
507                Value::Array(items)
508            }
509            ValueRef::Map { len, .. } => {
510                let mut entries = Vec::with_capacity(len);
511                for (k, v) in self.map_entries().into_iter().flatten() {
512                    entries.push((k.to_owned_value()?, v.to_owned_value()?));
513                }
514                Value::Map(entries)
515            }
516        })
517    }
518}
519
520/// Items of a validated array (or keys and values of a map, in order).
521#[derive(Debug, Clone)]
522pub struct Items<'a> {
523    rest: &'a [u8],
524    remaining: usize,
525    depth: usize,
526}
527
528impl<'a> Iterator for Items<'a> {
529    type Item = ValueRef<'a>;
530
531    fn next(&mut self) -> Option<ValueRef<'a>> {
532        if self.remaining == 0 {
533            return None;
534        }
535        self.remaining -= 1;
536        // Validated when the container was decoded, so this cannot fail.
537        let (value, consumed) = unpack_ref(self.rest, self.depth).ok()?;
538        self.rest = &self.rest[consumed..];
539        Some(value)
540    }
541}
542
543/// Entries of a validated map.
544#[derive(Debug, Clone)]
545pub struct Entries<'a>(Items<'a>);
546
547impl<'a> Iterator for Entries<'a> {
548    type Item = (ValueRef<'a>, ValueRef<'a>);
549
550    fn next(&mut self) -> Option<Self::Item> {
551        Some((self.0.next()?, self.0.next()?))
552    }
553}
554
555/// Decode one value from the start of `data` without copying, returning it
556/// and the bytes consumed. Nested arrays and maps are validated in full.
557pub fn unpack_ref(data: &[u8], depth: usize) -> Result<(ValueRef<'_>, usize), Error> {
558    if data.is_empty() {
559        return Err(Error::UnexpectedEof);
560    }
561    if depth > MAX_DEPTH {
562        return Err(Error::MaxDepthExceeded);
563    }
564    let b = data[0];
565    match b {
566        // positive fixint: 0x00..0x7f
567        0x00..=0x7f => Ok((ValueRef::UInt(b as u64), 1)),
568
569        // fixmap: 0x80..0x8f
570        0x80..=0x8f => unpack_map_ref(data, 1, (b & 0x0f) as usize, depth),
571
572        // fixarray: 0x90..0x9f
573        0x90..=0x9f => unpack_array_ref(data, 1, (b & 0x0f) as usize, depth),
574
575        // fixstr: 0xa0..0xbf
576        0xa0..=0xbf => unpack_str_ref(data, 1, (b & 0x1f) as usize),
577
578        // nil
579        0xc0 => Ok((ValueRef::Nil, 1)),
580
581        // (unused)
582        0xc1 => Err(Error::UnsupportedFormat(b)),
583
584        // bool
585        0xc2 => Ok((ValueRef::Bool(false), 1)),
586        0xc3 => Ok((ValueRef::Bool(true), 1)),
587
588        // float32
589        0xca => {
590            ensure_len(data, 5)?;
591            let bits = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
592            Ok((ValueRef::Float(f32::from_bits(bits) as f64), 5))
593        }
594
595        // float64
596        0xcb => {
597            ensure_len(data, 9)?;
598            let bits = u64::from_be_bytes([
599                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
600            ]);
601            Ok((ValueRef::Float(f64::from_bits(bits)), 9))
602        }
603
604        // bin8, bin16, bin32
605        0xc4 => {
606            ensure_len(data, 2)?;
607            unpack_bin_ref(data, 2, data[1] as usize)
608        }
609        0xc5 => {
610            ensure_len(data, 3)?;
611            unpack_bin_ref(data, 3, u16::from_be_bytes([data[1], data[2]]) as usize)
612        }
613        0xc6 => {
614            ensure_len(data, 5)?;
615            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
616            unpack_bin_ref(data, 5, len)
617        }
618
619        // uint8
620        0xcc => {
621            ensure_len(data, 2)?;
622            Ok((ValueRef::UInt(data[1] as u64), 2))
623        }
624
625        // uint16
626        0xcd => {
627            ensure_len(data, 3)?;
628            let v = u16::from_be_bytes([data[1], data[2]]);
629            Ok((ValueRef::UInt(v as u64), 3))
630        }
631
632        // uint32
633        0xce => {
634            ensure_len(data, 5)?;
635            let v = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
636            Ok((ValueRef::UInt(v as u64), 5))
637        }
638
639        // uint64
640        0xcf => {
641            ensure_len(data, 9)?;
642            let v = u64::from_be_bytes([
643                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
644            ]);
645            Ok((ValueRef::UInt(v), 9))
646        }
647
648        // int8
649        0xd0 => {
650            ensure_len(data, 2)?;
651            Ok((ValueRef::Int(data[1] as i8 as i64), 2))
652        }
653
654        // int16
655        0xd1 => {
656            ensure_len(data, 3)?;
657            let v = i16::from_be_bytes([data[1], data[2]]);
658            Ok((ValueRef::Int(v as i64), 3))
659        }
660
661        // int32
662        0xd2 => {
663            ensure_len(data, 5)?;
664            let v = i32::from_be_bytes([data[1], data[2], data[3], data[4]]);
665            Ok((ValueRef::Int(v as i64), 5))
666        }
667
668        // int64
669        0xd3 => {
670            ensure_len(data, 9)?;
671            let v = i64::from_be_bytes([
672                data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
673            ]);
674            Ok((ValueRef::Int(v), 9))
675        }
676
677        // str8, str16, str32
678        0xd9 => {
679            ensure_len(data, 2)?;
680            unpack_str_ref(data, 2, data[1] as usize)
681        }
682        0xda => {
683            ensure_len(data, 3)?;
684            unpack_str_ref(data, 3, u16::from_be_bytes([data[1], data[2]]) as usize)
685        }
686        0xdb => {
687            ensure_len(data, 5)?;
688            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
689            unpack_str_ref(data, 5, len)
690        }
691
692        // array16, array32
693        0xdc => {
694            ensure_len(data, 3)?;
695            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
696            unpack_array_ref(data, 3, len, depth)
697        }
698        0xdd => {
699            ensure_len(data, 5)?;
700            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
701            unpack_array_ref(data, 5, len, depth)
702        }
703
704        // map16, map32
705        0xde => {
706            ensure_len(data, 3)?;
707            let len = u16::from_be_bytes([data[1], data[2]]) as usize;
708            unpack_map_ref(data, 3, len, depth)
709        }
710        0xdf => {
711            ensure_len(data, 5)?;
712            let len = u32::from_be_bytes([data[1], data[2], data[3], data[4]]) as usize;
713            unpack_map_ref(data, 5, len, depth)
714        }
715
716        // negative fixint: 0xe0..0xff
717        0xe0..=0xff => Ok((ValueRef::Int(b as i8 as i64), 1)),
718
719        _ => Err(Error::UnsupportedFormat(b)),
720    }
721}
722
723fn unpack_bin_ref(data: &[u8], offset: usize, len: usize) -> Result<(ValueRef<'_>, usize), Error> {
724    let end = offset.checked_add(len).ok_or(Error::UnexpectedEof)?;
725    ensure_len(data, end)?;
726    Ok((ValueRef::Bin(&data[offset..end]), end))
727}
728
729fn unpack_str_ref(data: &[u8], offset: usize, len: usize) -> Result<(ValueRef<'_>, usize), Error> {
730    let end = offset.checked_add(len).ok_or(Error::UnexpectedEof)?;
731    ensure_len(data, end)?;
732    let s = core::str::from_utf8(&data[offset..end]).map_err(|_| Error::InvalidUtf8)?;
733    Ok((ValueRef::Str(s), end))
734}
735
736/// Validate `count` values after `start` at `depth + 1`; returns the offset
737/// after them.
738fn skip_items(data: &[u8], start: usize, count: usize, depth: usize) -> Result<usize, Error> {
739    let mut offset = start;
740    for _ in 0..count {
741        let (_, consumed) = unpack_ref(&data[offset..], depth + 1)?;
742        offset += consumed;
743    }
744    Ok(offset)
745}
746
747fn unpack_array_ref(
748    data: &[u8],
749    start: usize,
750    count: usize,
751    depth: usize,
752) -> Result<(ValueRef<'_>, usize), Error> {
753    if count > data.len().saturating_sub(start) {
754        return Err(Error::UnexpectedEof);
755    }
756    let end = skip_items(data, start, count, depth)?;
757    Ok((
758        ValueRef::Array {
759            len: count,
760            items: &data[start..end],
761            depth,
762        },
763        end,
764    ))
765}
766
767fn unpack_map_ref(
768    data: &[u8],
769    start: usize,
770    count: usize,
771    depth: usize,
772) -> Result<(ValueRef<'_>, usize), Error> {
773    let items = count
774        .checked_mul(2)
775        .filter(|items| *items <= data.len().saturating_sub(start))
776        .ok_or(Error::UnexpectedEof)?;
777    let end = skip_items(data, start, items, depth)?;
778    Ok((
779        ValueRef::Map {
780            len: count,
781            entries: &data[start..end],
782            depth,
783        },
784        end,
785    ))
786}
787
788#[cfg(test)]
789mod tests {
790    use super::*;
791
792    /// Encoded values that exercise every format, including encodings
793    /// [`pack`] never writes (float32, non-minimal integers and lengths).
794    fn encoded_corpus() -> Vec<Vec<u8>> {
795        let mut corpus: Vec<Vec<u8>> = vec![
796            vec![0xc0],
797            vec![0xc2],
798            vec![0xc3],
799            vec![0x7f],
800            vec![0xe0],
801            vec![0xcc, 0x05],
802            vec![0xcd, 0x00, 0x05],
803            vec![0xcf, 0, 0, 0, 0, 0, 0, 0, 1],
804            vec![0xd0, 0x05],
805            vec![0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00],
806            vec![0xca, 0x3f, 0x80, 0x00, 0x00],
807            vec![0xcb, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
808            vec![0xc4, 0x02, 0xaa, 0xbb],
809            vec![0xc5, 0x00, 0x01, 0xaa],
810            vec![0xa3, b'a', b'b', b'c'],
811            vec![0xd9, 0x01, b'x'],
812            vec![0x93, 0x01, 0xc4, 0x01, 0xff, 0x92, 0xc0, 0xa1, b'k'],
813            vec![0xdc, 0x00, 0x02, 0xc3, 0xc2],
814            vec![
815                0x82, 0xa1, b'a', 0x01, 0xa1, b'a', 0x92, 0x02, 0xca, 0, 0, 0, 0,
816            ],
817            vec![0xde, 0x00, 0x01, 0x01, 0x80],
818        ];
819        corpus.push(pack(&Value::Array(vec![
820            Value::Float(1.5),
821            Value::Bin(vec![7; 300]),
822            Value::Str("s".repeat(40)),
823            Value::Array((0..20).map(Value::UInt).collect()),
824            Value::Map((0..20).map(|i| (Value::Int(-i), Value::Nil)).collect()),
825        ])));
826        corpus
827    }
828
829    #[test]
830    fn packing_a_borrowed_value_matches_packing_its_owned_form() {
831        let mut inputs = encoded_corpus();
832        // Plus every prefix and one-byte corruption of the corpus, so the
833        // accepted set is wide and the rejected one is checked to agree.
834        let mut extra = Vec::new();
835        for input in &inputs {
836            for end in 0..input.len() {
837                extra.push(input[..end].to_vec());
838            }
839            for i in 0..input.len() {
840                for byte in [0x00, 0x7f, 0x90, 0xc4, 0xca, 0xdc, 0xff] {
841                    let mut corrupt = input.clone();
842                    corrupt[i] = byte;
843                    extra.push(corrupt);
844                }
845            }
846        }
847        inputs.extend(extra);
848        let mut accepted = 0;
849        for input in &inputs {
850            let owned = unpack_exact(input);
851            let borrowed = unpack_exact_ref(input);
852            assert_eq!(owned.is_ok(), borrowed.is_ok(), "{input:02x?}");
853            if let (Ok(owned), Ok(borrowed)) = (owned, borrowed) {
854                let mut packed = Vec::new();
855                pack_ref_into(borrowed, &mut packed);
856                assert_eq!(packed, pack(&owned), "{input:02x?}");
857                accepted += 1;
858            }
859        }
860        assert!(accepted > 100);
861    }
862
863    fn roundtrip(v: &Value) -> Value {
864        let packed = pack(v);
865        let (unpacked, consumed) = unpack(&packed).unwrap();
866        assert_eq!(consumed, packed.len(), "all bytes consumed");
867        unpacked
868    }
869
870    #[test]
871    fn test_nil() {
872        let packed = pack(&Value::Nil);
873        assert_eq!(packed, vec![0xc0]);
874        assert_eq!(roundtrip(&Value::Nil), Value::Nil);
875    }
876
877    #[test]
878    fn test_bool() {
879        assert_eq!(pack(&Value::Bool(true)), vec![0xc3]);
880        assert_eq!(pack(&Value::Bool(false)), vec![0xc2]);
881        assert_eq!(roundtrip(&Value::Bool(true)), Value::Bool(true));
882        assert_eq!(roundtrip(&Value::Bool(false)), Value::Bool(false));
883    }
884
885    #[test]
886    fn test_positive_fixint() {
887        assert_eq!(pack(&Value::UInt(0)), vec![0x00]);
888        assert_eq!(pack(&Value::UInt(127)), vec![0x7f]);
889        assert_eq!(roundtrip(&Value::UInt(0)), Value::UInt(0));
890        assert_eq!(roundtrip(&Value::UInt(42)), Value::UInt(42));
891        assert_eq!(roundtrip(&Value::UInt(127)), Value::UInt(127));
892    }
893
894    #[test]
895    fn test_uint8() {
896        assert_eq!(pack(&Value::UInt(128)), vec![0xcc, 0x80]);
897        assert_eq!(pack(&Value::UInt(255)), vec![0xcc, 0xff]);
898        assert_eq!(roundtrip(&Value::UInt(128)), Value::UInt(128));
899        assert_eq!(roundtrip(&Value::UInt(255)), Value::UInt(255));
900    }
901
902    #[test]
903    fn test_uint16() {
904        assert_eq!(pack(&Value::UInt(256)), vec![0xcd, 0x01, 0x00]);
905        assert_eq!(roundtrip(&Value::UInt(256)), Value::UInt(256));
906        assert_eq!(roundtrip(&Value::UInt(0xFFFF)), Value::UInt(0xFFFF));
907    }
908
909    #[test]
910    fn test_uint32() {
911        assert_eq!(
912            pack(&Value::UInt(0x10000)),
913            vec![0xce, 0x00, 0x01, 0x00, 0x00]
914        );
915        assert_eq!(roundtrip(&Value::UInt(0x10000)), Value::UInt(0x10000));
916        assert_eq!(roundtrip(&Value::UInt(0xFFFFFFFF)), Value::UInt(0xFFFFFFFF));
917    }
918
919    #[test]
920    fn test_uint64() {
921        let big = 0x1_0000_0000u64;
922        assert_eq!(roundtrip(&Value::UInt(big)), Value::UInt(big));
923        let huge = u64::MAX;
924        assert_eq!(roundtrip(&Value::UInt(huge)), Value::UInt(huge));
925    }
926
927    #[test]
928    fn test_negative_fixint() {
929        // -1 = 0xff, -32 = 0xe0
930        assert_eq!(pack(&Value::Int(-1)), vec![0xff]);
931        assert_eq!(pack(&Value::Int(-32)), vec![0xe0]);
932        assert_eq!(roundtrip(&Value::Int(-1)), Value::Int(-1));
933        assert_eq!(roundtrip(&Value::Int(-32)), Value::Int(-32));
934    }
935
936    #[test]
937    fn test_int8() {
938        assert_eq!(pack(&Value::Int(-33)), vec![0xd0, 0xdf]);
939        assert_eq!(roundtrip(&Value::Int(-33)), Value::Int(-33));
940        assert_eq!(roundtrip(&Value::Int(-128)), Value::Int(-128));
941    }
942
943    #[test]
944    fn test_int16() {
945        assert_eq!(roundtrip(&Value::Int(-129)), Value::Int(-129));
946        assert_eq!(roundtrip(&Value::Int(-32768)), Value::Int(-32768));
947    }
948
949    #[test]
950    fn test_int32() {
951        assert_eq!(roundtrip(&Value::Int(-32769)), Value::Int(-32769));
952    }
953
954    #[test]
955    fn test_positive_int_packed_as_uint() {
956        // Positive values always encode as uint format
957        let packed = pack(&Value::Int(42));
958        assert_eq!(packed, vec![42]); // positive fixint
959    }
960
961    #[test]
962    fn test_fixstr() {
963        let v = Value::Str(String::from("t"));
964        let packed = pack(&v);
965        assert_eq!(packed[0], 0xa1); // fixstr len=1
966        assert_eq!(roundtrip(&v), v);
967
968        let v = Value::Str(String::from("hello"));
969        assert_eq!(roundtrip(&v), v);
970
971        // Empty string
972        let v = Value::Str(String::new());
973        assert_eq!(pack(&v), vec![0xa0]);
974        assert_eq!(roundtrip(&v), v);
975    }
976
977    #[test]
978    fn test_str8() {
979        let s: String = "a".repeat(32);
980        let v = Value::Str(s);
981        let packed = pack(&v);
982        assert_eq!(packed[0], 0xd9);
983        assert_eq!(packed[1], 32);
984        assert_eq!(roundtrip(&v), v);
985    }
986
987    #[test]
988    fn test_bin8() {
989        let v = Value::Bin(vec![1, 2, 3]);
990        let packed = pack(&v);
991        assert_eq!(packed[0], 0xc4);
992        assert_eq!(packed[1], 3);
993        assert_eq!(roundtrip(&v), v);
994    }
995
996    #[test]
997    fn test_bin16() {
998        let data = vec![0xAB; 300];
999        let v = Value::Bin(data);
1000        let packed = pack(&v);
1001        assert_eq!(packed[0], 0xc5);
1002        assert_eq!(roundtrip(&v), v);
1003    }
1004
1005    #[test]
1006    fn test_bin32() {
1007        // bin32 threshold is > 65535 bytes, skip actual large allocation but
1008        // test the format byte by manually checking a 0-length edge
1009        let data = vec![0xCD; 70000];
1010        let v = Value::Bin(data);
1011        let packed = pack(&v);
1012        assert_eq!(packed[0], 0xc6);
1013        assert_eq!(roundtrip(&v), v);
1014    }
1015
1016    #[test]
1017    fn test_fixarray() {
1018        let v = Value::Array(vec![Value::UInt(1), Value::UInt(2), Value::UInt(3)]);
1019        let packed = pack(&v);
1020        assert_eq!(packed[0], 0x93); // fixarray len=3
1021        assert_eq!(roundtrip(&v), v);
1022
1023        // Empty array
1024        let v = Value::Array(vec![]);
1025        assert_eq!(pack(&v), vec![0x90]);
1026        assert_eq!(roundtrip(&v), v);
1027    }
1028
1029    #[test]
1030    fn test_fixmap() {
1031        let v = Value::Map(vec![
1032            (Value::Str(String::from("a")), Value::UInt(1)),
1033            (Value::Str(String::from("b")), Value::UInt(2)),
1034        ]);
1035        let packed = pack(&v);
1036        assert_eq!(packed[0], 0x82); // fixmap len=2
1037        assert_eq!(roundtrip(&v), v);
1038    }
1039
1040    #[test]
1041    fn test_nested_structure() {
1042        let v = Value::Map(vec![
1043            (Value::Str(String::from("t")), Value::UInt(1000)),
1044            (Value::Str(String::from("m")), Value::Bin(vec![0xAA; 10])),
1045            (Value::Str(String::from("q")), Value::Nil),
1046        ]);
1047        assert_eq!(roundtrip(&v), v);
1048    }
1049
1050    #[test]
1051    fn test_pack_str_map() {
1052        let packed = pack_str_map(&[("x", Value::UInt(42)), ("y", Value::Bool(true))]);
1053        let (v, _) = unpack(&packed).unwrap();
1054        assert_eq!(v.map_get("x").unwrap().as_uint(), Some(42));
1055        assert_eq!(v.map_get("y").unwrap().as_bool(), Some(true));
1056    }
1057
1058    #[test]
1059    fn test_map_get_missing_key() {
1060        let v = Value::Map(vec![(Value::Str(String::from("a")), Value::UInt(1))]);
1061        assert!(v.map_get("b").is_none());
1062    }
1063
1064    #[test]
1065    fn test_hmu_array_format() {
1066        // HMU format: [segment_int, hashmap_bytes]
1067        let v = Value::Array(vec![
1068            Value::UInt(2),
1069            Value::Bin(vec![0x11, 0x22, 0x33, 0x44, 0xAA, 0xBB, 0xCC, 0xDD]),
1070        ]);
1071        assert_eq!(roundtrip(&v), v);
1072    }
1073
1074    #[test]
1075    fn test_decode_error_eof() {
1076        assert_eq!(unpack(&[]), Err(Error::UnexpectedEof));
1077        // bin8 with length but no data
1078        assert_eq!(unpack(&[0xc4, 0x05]), Err(Error::UnexpectedEof));
1079    }
1080
1081    #[test]
1082    fn test_declared_array_length_cannot_force_large_allocation() {
1083        let data = [0xdd, 0xff, 0xff, 0xff, 0xff];
1084        assert_eq!(unpack(&data), Err(Error::UnexpectedEof));
1085    }
1086
1087    #[test]
1088    fn test_declared_map_length_cannot_force_large_allocation() {
1089        let data = [0xdf, 0x7f, 0xff, 0xff, 0xff];
1090        assert_eq!(unpack(&data), Err(Error::UnexpectedEof));
1091    }
1092
1093    #[test]
1094    fn test_unpack_exact_trailing() {
1095        let packed = pack(&Value::UInt(42));
1096        let mut with_extra = packed.clone();
1097        with_extra.push(0x00);
1098        assert!(unpack_exact(&with_extra).is_err());
1099        assert!(unpack_exact(&packed).is_ok());
1100    }
1101
1102    #[test]
1103    fn test_value_accessors() {
1104        assert_eq!(Value::UInt(42).as_uint(), Some(42));
1105        assert_eq!(Value::UInt(42).as_int(), None);
1106        assert_eq!(Value::UInt(42).as_integer(), Some(42));
1107        assert_eq!(Value::Int(-5).as_integer(), Some(-5));
1108        assert_eq!(Value::Bool(true).as_bool(), Some(true));
1109        assert_eq!(Value::Bin(vec![1]).as_bin(), Some(&[1u8][..]));
1110        assert_eq!(Value::Str(String::from("x")).as_str(), Some("x"));
1111        assert!(Value::Nil.is_nil());
1112    }
1113
1114    #[test]
1115    fn test_max_depth_exceeded() {
1116        // Build deeply nested arrays: [[[[...]]]] beyond MAX_DEPTH
1117        let mut data = Vec::new();
1118        data.extend(core::iter::repeat_n(0x91, MAX_DEPTH + 2)); // fixarray of length 1
1119        data.push(0x01); // innermost value: uint 1
1120        assert_eq!(unpack(&data), Err(Error::MaxDepthExceeded));
1121    }
1122
1123    #[test]
1124    fn test_depth_within_limit() {
1125        // Build nested arrays within limit (depth 5)
1126        let mut data = Vec::new();
1127        data.extend(core::iter::repeat_n(0x91, 5)); // fixarray of length 1
1128        data.push(0x01); // innermost value
1129        let (val, _) = unpack(&data).unwrap();
1130        // Should be Array([Array([Array([Array([Array([UInt(1)])])])])])
1131        let mut current = &val;
1132        for _ in 0..5 {
1133            current = &current.as_array().unwrap()[0];
1134        }
1135        assert_eq!(current.as_uint(), Some(1));
1136    }
1137
1138    #[test]
1139    fn test_int64_roundtrip() {
1140        let v = Value::Int(i64::MIN);
1141        assert_eq!(roundtrip(&v), v);
1142        let v = Value::Int(-2_147_483_649); // beyond i32 range
1143        assert_eq!(roundtrip(&v), v);
1144    }
1145
1146    #[test]
1147    fn test_str16_roundtrip() {
1148        let s: String = "x".repeat(256);
1149        let v = Value::Str(s);
1150        let packed = pack(&v);
1151        assert_eq!(packed[0], 0xda); // str16
1152        assert_eq!(roundtrip(&v), v);
1153    }
1154
1155    #[test]
1156    fn test_array16_roundtrip() {
1157        let items: Vec<Value> = (0..16).map(Value::UInt).collect();
1158        let v = Value::Array(items);
1159        let packed = pack(&v);
1160        assert_eq!(packed[0], 0xdc); // array16
1161        assert_eq!(roundtrip(&v), v);
1162    }
1163
1164    #[test]
1165    fn test_map16_roundtrip() {
1166        let entries: Vec<(Value, Value)> = (0..16)
1167            .map(|i| (Value::UInt(i), Value::Bool(i % 2 == 0)))
1168            .collect();
1169        let v = Value::Map(entries);
1170        let packed = pack(&v);
1171        assert_eq!(packed[0], 0xde); // map16
1172        assert_eq!(roundtrip(&v), v);
1173    }
1174
1175    #[test]
1176    fn test_unsupported_format() {
1177        // 0xc1 is unused/never valid
1178        assert_eq!(unpack(&[0xc1]), Err(Error::UnsupportedFormat(0xc1)));
1179    }
1180}