Skip to main content

scirs2_io/formats/
msgpack.rs

1//! MessagePack serialization inside the `formats` module.
2//!
3//! A thin, self-contained implementation of the MessagePack spec in pure Rust.
4//! Unlike the top-level `msgpack` module (which bridges to serde_json), this
5//! module exposes a low-level `MsgPackValue` + `MsgPackWriter` / `MsgPackReader`
6//! API that is useful when you need fine-grained control over the wire encoding.
7//!
8//! ## Supported formats
9//! - Positive fixint (0..127), negative fixint (-32..-1)
10//! - nil, bool
11//! - uint8/16/32/64, int8/16/32/64
12//! - float32 / float64
13//! - fixstr, str8/16/32
14//! - bin8/16/32
15//! - fixarray, array16/32
16//! - fixmap, map16/32
17//! - ext types (fixext 1/2/4/8/16, ext8/16/32)
18
19use std::io::{Cursor, Read};
20
21use crate::error::{IoError, Result};
22
23// ─────────────────────────────── byte constants ──────────────────────────────
24
25const FMT_NIL: u8 = 0xc0;
26const FMT_FALSE: u8 = 0xc2;
27const FMT_TRUE: u8 = 0xc3;
28const FMT_BIN8: u8 = 0xc4;
29const FMT_BIN16: u8 = 0xc5;
30const FMT_BIN32: u8 = 0xc6;
31const FMT_EXT8: u8 = 0xc7;
32const FMT_EXT16: u8 = 0xc8;
33const FMT_EXT32: u8 = 0xc9;
34const FMT_FLOAT32: u8 = 0xca;
35const FMT_FLOAT64: u8 = 0xcb;
36const FMT_UINT8: u8 = 0xcc;
37const FMT_UINT16: u8 = 0xcd;
38const FMT_UINT32: u8 = 0xce;
39const FMT_UINT64: u8 = 0xcf;
40const FMT_INT8: u8 = 0xd0;
41const FMT_INT16: u8 = 0xd1;
42const FMT_INT32: u8 = 0xd2;
43const FMT_INT64: u8 = 0xd3;
44const FMT_FIXEXT1: u8 = 0xd4;
45const FMT_FIXEXT2: u8 = 0xd5;
46const FMT_FIXEXT4: u8 = 0xd6;
47const FMT_FIXEXT8: u8 = 0xd7;
48const FMT_FIXEXT16: u8 = 0xd8;
49const FMT_STR8: u8 = 0xd9;
50const FMT_STR16: u8 = 0xda;
51const FMT_STR32: u8 = 0xdb;
52const FMT_ARRAY16: u8 = 0xdc;
53const FMT_ARRAY32: u8 = 0xdd;
54const FMT_MAP16: u8 = 0xde;
55const FMT_MAP32: u8 = 0xdf;
56
57// ─────────────────────────────── Value type ──────────────────────────────────
58
59/// A MessagePack value.
60#[derive(Debug, Clone, PartialEq)]
61pub enum MsgPackValue {
62    /// nil / null
63    Nil,
64    /// Boolean
65    Bool(bool),
66    /// Signed integer (covers all int types)
67    Int(i64),
68    /// Unsigned integer (used when value > i64::MAX)
69    UInt(u64),
70    /// 32-bit float
71    Float32(f32),
72    /// 64-bit float
73    Float64(f64),
74    /// UTF-8 string
75    Str(String),
76    /// Raw binary data
77    Bin(Vec<u8>),
78    /// Array of values
79    Array(Vec<MsgPackValue>),
80    /// Map of key-value pairs
81    Map(Vec<(MsgPackValue, MsgPackValue)>),
82    /// Extension type: (type_id, bytes)
83    Ext(i8, Vec<u8>),
84}
85
86// ─────────────────────────────── Encoder ─────────────────────────────────────
87
88/// Low-level MessagePack writer.
89///
90/// Push individual values into an internal buffer, then call [`MsgPackWriter::into_bytes`]
91/// to get the encoded byte slice.
92///
93/// # Example
94/// ```
95/// use scirs2_io::formats::msgpack::{MsgPackWriter, MsgPackReader};
96///
97/// let mut w = MsgPackWriter::new();
98/// w.write_map_header(1);
99/// w.write_str("answer");
100/// w.write_int(42);
101/// let bytes = w.into_bytes();
102///
103/// let mut r = MsgPackReader::new(&bytes);
104/// let value = r.read_value().expect("decode failed");
105/// ```
106#[derive(Debug, Default)]
107pub struct MsgPackWriter {
108    buf: Vec<u8>,
109}
110
111impl MsgPackWriter {
112    /// Create a new, empty writer.
113    pub fn new() -> Self {
114        Self { buf: Vec::new() }
115    }
116
117    /// Consume the writer and return the encoded bytes.
118    pub fn into_bytes(self) -> Vec<u8> {
119        self.buf
120    }
121
122    /// Borrow the current internal buffer.
123    pub fn as_bytes(&self) -> &[u8] {
124        &self.buf
125    }
126
127    /// Write a nil value.
128    pub fn write_nil(&mut self) {
129        self.buf.push(FMT_NIL);
130    }
131
132    /// Write a boolean value.
133    pub fn write_bool(&mut self, v: bool) {
134        self.buf.push(if v { FMT_TRUE } else { FMT_FALSE });
135    }
136
137    /// Write a signed integer using the smallest possible representation.
138    pub fn write_int(&mut self, v: i64) {
139        if (0..=127).contains(&v) {
140            self.buf.push(v as u8);
141        } else if (-32..=-1).contains(&v) {
142            self.buf.push((v as i8) as u8);
143        } else if v >= 0 {
144            let u = v as u64;
145            if u <= u8::MAX as u64 {
146                self.buf.extend_from_slice(&[FMT_UINT8, u as u8]);
147            } else if u <= u16::MAX as u64 {
148                self.buf.push(FMT_UINT16);
149                self.buf.extend_from_slice(&(u as u16).to_be_bytes());
150            } else if u <= u32::MAX as u64 {
151                self.buf.push(FMT_UINT32);
152                self.buf.extend_from_slice(&(u as u32).to_be_bytes());
153            } else {
154                self.buf.push(FMT_UINT64);
155                self.buf.extend_from_slice(&u.to_be_bytes());
156            }
157        } else if v >= i8::MIN as i64 {
158            self.buf.extend_from_slice(&[FMT_INT8, v as u8]);
159        } else if v >= i16::MIN as i64 {
160            self.buf.push(FMT_INT16);
161            self.buf.extend_from_slice(&(v as i16).to_be_bytes());
162        } else if v >= i32::MIN as i64 {
163            self.buf.push(FMT_INT32);
164            self.buf.extend_from_slice(&(v as i32).to_be_bytes());
165        } else {
166            self.buf.push(FMT_INT64);
167            self.buf.extend_from_slice(&v.to_be_bytes());
168        }
169    }
170
171    /// Write an unsigned integer using the smallest possible representation.
172    pub fn write_uint(&mut self, v: u64) {
173        if v <= 127 {
174            self.buf.push(v as u8);
175        } else if v <= u8::MAX as u64 {
176            self.buf.extend_from_slice(&[FMT_UINT8, v as u8]);
177        } else if v <= u16::MAX as u64 {
178            self.buf.push(FMT_UINT16);
179            self.buf.extend_from_slice(&(v as u16).to_be_bytes());
180        } else if v <= u32::MAX as u64 {
181            self.buf.push(FMT_UINT32);
182            self.buf.extend_from_slice(&(v as u32).to_be_bytes());
183        } else {
184            self.buf.push(FMT_UINT64);
185            self.buf.extend_from_slice(&v.to_be_bytes());
186        }
187    }
188
189    /// Write a 64-bit float (f64).
190    pub fn write_float(&mut self, v: f64) {
191        self.buf.push(FMT_FLOAT64);
192        self.buf.extend_from_slice(&v.to_bits().to_be_bytes());
193    }
194
195    /// Write a 32-bit float (f32).
196    pub fn write_float32(&mut self, v: f32) {
197        self.buf.push(FMT_FLOAT32);
198        self.buf.extend_from_slice(&v.to_bits().to_be_bytes());
199    }
200
201    /// Write a UTF-8 string.
202    pub fn write_str(&mut self, s: &str) {
203        let bytes = s.as_bytes();
204        let n = bytes.len();
205        if n <= 31 {
206            self.buf.push(0xa0 | (n as u8));
207        } else if n <= 255 {
208            self.buf.extend_from_slice(&[FMT_STR8, n as u8]);
209        } else if n <= 65535 {
210            self.buf.push(FMT_STR16);
211            self.buf.extend_from_slice(&(n as u16).to_be_bytes());
212        } else {
213            self.buf.push(FMT_STR32);
214            self.buf.extend_from_slice(&(n as u32).to_be_bytes());
215        }
216        self.buf.extend_from_slice(bytes);
217    }
218
219    /// Write raw binary data.
220    pub fn write_bin(&mut self, b: &[u8]) {
221        let n = b.len();
222        if n <= 255 {
223            self.buf.extend_from_slice(&[FMT_BIN8, n as u8]);
224        } else if n <= 65535 {
225            self.buf.push(FMT_BIN16);
226            self.buf.extend_from_slice(&(n as u16).to_be_bytes());
227        } else {
228            self.buf.push(FMT_BIN32);
229            self.buf.extend_from_slice(&(n as u32).to_be_bytes());
230        }
231        self.buf.extend_from_slice(b);
232    }
233
234    /// Write an array header.  You must write exactly `n` elements after this call.
235    pub fn write_array_header(&mut self, n: usize) {
236        if n <= 15 {
237            self.buf.push(0x90 | (n as u8));
238        } else if n <= 65535 {
239            self.buf.push(FMT_ARRAY16);
240            self.buf.extend_from_slice(&(n as u16).to_be_bytes());
241        } else {
242            self.buf.push(FMT_ARRAY32);
243            self.buf.extend_from_slice(&(n as u32).to_be_bytes());
244        }
245    }
246
247    /// Write a map header.  You must write exactly `n` key-value pairs after this call.
248    pub fn write_map_header(&mut self, n: usize) {
249        if n <= 15 {
250            self.buf.push(0x80 | (n as u8));
251        } else if n <= 65535 {
252            self.buf.push(FMT_MAP16);
253            self.buf.extend_from_slice(&(n as u16).to_be_bytes());
254        } else {
255            self.buf.push(FMT_MAP32);
256            self.buf.extend_from_slice(&(n as u32).to_be_bytes());
257        }
258    }
259
260    /// Write an extension type.
261    pub fn write_ext(&mut self, type_id: i8, data: &[u8]) {
262        let n = data.len();
263        let tid = type_id as u8;
264        match n {
265            1 => self.buf.extend_from_slice(&[FMT_FIXEXT1, tid]),
266            2 => self.buf.extend_from_slice(&[FMT_FIXEXT2, tid]),
267            4 => self.buf.extend_from_slice(&[FMT_FIXEXT4, tid]),
268            8 => self.buf.extend_from_slice(&[FMT_FIXEXT8, tid]),
269            16 => self.buf.extend_from_slice(&[FMT_FIXEXT16, tid]),
270            _ => {
271                if n <= 255 {
272                    self.buf.extend_from_slice(&[FMT_EXT8, n as u8, tid]);
273                } else if n <= 65535 {
274                    self.buf.push(FMT_EXT16);
275                    self.buf.extend_from_slice(&(n as u16).to_be_bytes());
276                    self.buf.push(tid);
277                } else {
278                    self.buf.push(FMT_EXT32);
279                    self.buf.extend_from_slice(&(n as u32).to_be_bytes());
280                    self.buf.push(tid);
281                }
282            }
283        }
284        self.buf.extend_from_slice(data);
285    }
286
287    /// Recursively write a [`MsgPackValue`].
288    pub fn write_value(&mut self, value: &MsgPackValue) {
289        match value {
290            MsgPackValue::Nil => self.write_nil(),
291            MsgPackValue::Bool(b) => self.write_bool(*b),
292            MsgPackValue::Int(i) => self.write_int(*i),
293            MsgPackValue::UInt(u) => self.write_uint(*u),
294            MsgPackValue::Float32(f) => self.write_float32(*f),
295            MsgPackValue::Float64(f) => self.write_float(*f),
296            MsgPackValue::Str(s) => self.write_str(s),
297            MsgPackValue::Bin(b) => self.write_bin(b),
298            MsgPackValue::Array(arr) => {
299                self.write_array_header(arr.len());
300                for elem in arr {
301                    self.write_value(elem);
302                }
303            }
304            MsgPackValue::Map(map) => {
305                self.write_map_header(map.len());
306                for (k, v) in map {
307                    self.write_value(k);
308                    self.write_value(v);
309                }
310            }
311            MsgPackValue::Ext(tid, data) => self.write_ext(*tid, data),
312        }
313    }
314}
315
316// ─────────────────────────────── Decoder ─────────────────────────────────────
317
318/// Low-level MessagePack reader.
319///
320/// Wraps a byte slice and advances a position cursor as values are read.
321pub struct MsgPackReader<'a> {
322    data: &'a [u8],
323    pos: usize,
324}
325
326impl<'a> MsgPackReader<'a> {
327    /// Create a new reader over the given byte slice.
328    pub fn new(data: &'a [u8]) -> Self {
329        Self { data, pos: 0 }
330    }
331
332    /// Current read position.
333    pub fn position(&self) -> usize {
334        self.pos
335    }
336
337    /// Return true if all bytes have been consumed.
338    pub fn is_empty(&self) -> bool {
339        self.pos >= self.data.len()
340    }
341
342    fn read_bytes(&mut self, n: usize) -> Result<&'a [u8]> {
343        if self.pos + n > self.data.len() {
344            return Err(IoError::FormatError(format!(
345                "MsgPack: unexpected end of data (need {n} bytes at offset {})",
346                self.pos
347            )));
348        }
349        let slice = &self.data[self.pos..self.pos + n];
350        self.pos += n;
351        Ok(slice)
352    }
353
354    fn read_u8(&mut self) -> Result<u8> {
355        let b = self.read_bytes(1)?;
356        Ok(b[0])
357    }
358
359    fn read_u16_be(&mut self) -> Result<u16> {
360        let b = self.read_bytes(2)?;
361        Ok(u16::from_be_bytes([b[0], b[1]]))
362    }
363
364    fn read_u32_be(&mut self) -> Result<u32> {
365        let b = self.read_bytes(4)?;
366        Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
367    }
368
369    fn read_u64_be(&mut self) -> Result<u64> {
370        let b = self.read_bytes(8)?;
371        Ok(u64::from_be_bytes(b.try_into().map_err(|_| {
372            IoError::FormatError("MsgPack: bad u64 bytes".into())
373        })?))
374    }
375
376    fn read_str_bytes(&mut self, n: usize) -> Result<MsgPackValue> {
377        let raw = self.read_bytes(n)?;
378        let s = std::str::from_utf8(raw)
379            .map_err(|e| IoError::FormatError(format!("MsgPack: invalid UTF-8: {e}")))?
380            .to_owned();
381        Ok(MsgPackValue::Str(s))
382    }
383
384    fn read_array_items(&mut self, n: usize) -> Result<MsgPackValue> {
385        let mut arr = Vec::with_capacity(n);
386        for _ in 0..n {
387            arr.push(self.read_value()?);
388        }
389        Ok(MsgPackValue::Array(arr))
390    }
391
392    fn read_map_items(&mut self, n: usize) -> Result<MsgPackValue> {
393        let mut map = Vec::with_capacity(n);
394        for _ in 0..n {
395            let k = self.read_value()?;
396            let v = self.read_value()?;
397            map.push((k, v));
398        }
399        Ok(MsgPackValue::Map(map))
400    }
401
402    fn read_ext_data(&mut self, n: usize) -> Result<MsgPackValue> {
403        let type_byte = self.read_u8()?;
404        let type_id = type_byte as i8;
405        let data = self.read_bytes(n)?.to_vec();
406        Ok(MsgPackValue::Ext(type_id, data))
407    }
408
409    /// Read one MessagePack value from the current position.
410    pub fn read_value(&mut self) -> Result<MsgPackValue> {
411        let first = self.read_u8()?;
412
413        match first {
414            // positive fixint 0xxxxxxx
415            b if b & 0x80 == 0 => Ok(MsgPackValue::Int(b as i64)),
416            // fixmap 1000xxxx
417            b if b & 0xf0 == 0x80 => self.read_map_items((b & 0x0f) as usize),
418            // fixarray 1001xxxx
419            b if b & 0xf0 == 0x90 => self.read_array_items((b & 0x0f) as usize),
420            // fixstr 101xxxxx
421            b if b & 0xe0 == 0xa0 => self.read_str_bytes((b & 0x1f) as usize),
422            // negative fixint 111xxxxx
423            b if b & 0xe0 == 0xe0 => Ok(MsgPackValue::Int((b as i8) as i64)),
424            // named formats
425            FMT_NIL => Ok(MsgPackValue::Nil),
426            FMT_FALSE => Ok(MsgPackValue::Bool(false)),
427            FMT_TRUE => Ok(MsgPackValue::Bool(true)),
428            FMT_BIN8 => {
429                let n = self.read_u8()? as usize;
430                Ok(MsgPackValue::Bin(self.read_bytes(n)?.to_vec()))
431            }
432            FMT_BIN16 => {
433                let n = self.read_u16_be()? as usize;
434                Ok(MsgPackValue::Bin(self.read_bytes(n)?.to_vec()))
435            }
436            FMT_BIN32 => {
437                let n = self.read_u32_be()? as usize;
438                Ok(MsgPackValue::Bin(self.read_bytes(n)?.to_vec()))
439            }
440            FMT_EXT8 => {
441                let n = self.read_u8()? as usize;
442                self.read_ext_data(n)
443            }
444            FMT_EXT16 => {
445                let n = self.read_u16_be()? as usize;
446                self.read_ext_data(n)
447            }
448            FMT_EXT32 => {
449                let n = self.read_u32_be()? as usize;
450                self.read_ext_data(n)
451            }
452            FMT_FLOAT32 => {
453                let b = self.read_bytes(4)?;
454                let bits = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
455                Ok(MsgPackValue::Float32(f32::from_bits(bits)))
456            }
457            FMT_FLOAT64 => {
458                let bits = self.read_u64_be()?;
459                Ok(MsgPackValue::Float64(f64::from_bits(bits)))
460            }
461            FMT_UINT8 => Ok(MsgPackValue::UInt(self.read_u8()? as u64)),
462            FMT_UINT16 => Ok(MsgPackValue::UInt(self.read_u16_be()? as u64)),
463            FMT_UINT32 => Ok(MsgPackValue::UInt(self.read_u32_be()? as u64)),
464            FMT_UINT64 => Ok(MsgPackValue::UInt(self.read_u64_be()?)),
465            FMT_INT8 => Ok(MsgPackValue::Int(self.read_u8()? as i8 as i64)),
466            FMT_INT16 => {
467                let b = self.read_bytes(2)?;
468                Ok(MsgPackValue::Int(i16::from_be_bytes([b[0], b[1]]) as i64))
469            }
470            FMT_INT32 => {
471                let b = self.read_bytes(4)?;
472                Ok(MsgPackValue::Int(
473                    i32::from_be_bytes([b[0], b[1], b[2], b[3]]) as i64,
474                ))
475            }
476            FMT_INT64 => {
477                let b = self.read_bytes(8)?;
478                Ok(MsgPackValue::Int(i64::from_be_bytes(
479                    b.try_into()
480                        .map_err(|_| IoError::FormatError("MsgPack: bad i64 bytes".into()))?,
481                )))
482            }
483            FMT_FIXEXT1 => self.read_ext_data(1),
484            FMT_FIXEXT2 => self.read_ext_data(2),
485            FMT_FIXEXT4 => self.read_ext_data(4),
486            FMT_FIXEXT8 => self.read_ext_data(8),
487            FMT_FIXEXT16 => self.read_ext_data(16),
488            FMT_STR8 => {
489                let n = self.read_u8()? as usize;
490                self.read_str_bytes(n)
491            }
492            FMT_STR16 => {
493                let n = self.read_u16_be()? as usize;
494                self.read_str_bytes(n)
495            }
496            FMT_STR32 => {
497                let n = self.read_u32_be()? as usize;
498                self.read_str_bytes(n)
499            }
500            FMT_ARRAY16 => {
501                let n = self.read_u16_be()? as usize;
502                self.read_array_items(n)
503            }
504            FMT_ARRAY32 => {
505                let n = self.read_u32_be()? as usize;
506                self.read_array_items(n)
507            }
508            FMT_MAP16 => {
509                let n = self.read_u16_be()? as usize;
510                self.read_map_items(n)
511            }
512            FMT_MAP32 => {
513                let n = self.read_u32_be()? as usize;
514                self.read_map_items(n)
515            }
516            other => Err(IoError::FormatError(format!(
517                "MsgPack: unknown format byte 0x{other:02x} at offset {}",
518                self.pos - 1
519            ))),
520        }
521    }
522}
523
524// ─────────────────────────── Convenience encode/decode ───────────────────────
525
526/// Encode a `MsgPackValue` to bytes.
527pub fn msgpack_encode(value: &MsgPackValue) -> Vec<u8> {
528    let mut w = MsgPackWriter::new();
529    w.write_value(value);
530    w.into_bytes()
531}
532
533/// Decode a `MsgPackValue` from a byte slice.  Returns `(value, bytes_consumed)`.
534pub fn msgpack_decode(data: &[u8]) -> Result<(MsgPackValue, usize)> {
535    let mut r = MsgPackReader::new(data);
536    let value = r.read_value()?;
537    Ok((value, r.position()))
538}
539
540// ─────────────────────────────── round-trip helper ───────────────────────────
541
542/// Use a [`Cursor`] to hold bytes for cursor-based encode/decode operations.
543pub fn roundtrip(value: &MsgPackValue) -> Result<MsgPackValue> {
544    let encoded = msgpack_encode(value);
545    let (decoded, _) = msgpack_decode(&encoded)?;
546    Ok(decoded)
547}
548
549// ─────────────────────────────── Cursor-backed reader ────────────────────────
550
551/// A streaming MessagePack reader backed by an [`std::io::Read`] source.
552pub struct MsgPackStreamReader<R: Read> {
553    inner: Cursor<Vec<u8>>,
554    _source: std::marker::PhantomData<R>,
555}
556
557impl<R: Read> MsgPackStreamReader<R> {
558    /// Create from a `Read` source, eagerly reading all bytes into memory.
559    pub fn from_reader(mut source: R) -> Result<Self> {
560        let mut buf = Vec::new();
561        source.read_to_end(&mut buf).map_err(IoError::Io)?;
562        Ok(Self {
563            inner: Cursor::new(buf),
564            _source: std::marker::PhantomData,
565        })
566    }
567
568    /// Read the next MessagePack value.
569    pub fn read_next(&mut self) -> Result<MsgPackValue> {
570        let pos = self.inner.position() as usize;
571        let buf = self.inner.get_ref();
572        let remaining = &buf[pos..];
573        let mut reader = MsgPackReader::new(remaining);
574        let value = reader.read_value()?;
575        let consumed = reader.position();
576        self.inner.set_position((pos + consumed) as u64);
577        Ok(value)
578    }
579
580    /// True if the stream is exhausted.
581    pub fn is_done(&self) -> bool {
582        self.inner.position() >= self.inner.get_ref().len() as u64
583    }
584}
585
586// ─────────────────────────────── Tests ───────────────────────────────────────
587
588#[cfg(test)]
589mod tests {
590    use super::*;
591
592    fn rt(v: MsgPackValue) -> MsgPackValue {
593        roundtrip(&v).expect("roundtrip failed")
594    }
595
596    #[test]
597    fn test_nil_roundtrip() {
598        assert_eq!(rt(MsgPackValue::Nil), MsgPackValue::Nil);
599    }
600
601    #[test]
602    fn test_bool_roundtrip() {
603        assert_eq!(rt(MsgPackValue::Bool(true)), MsgPackValue::Bool(true));
604        assert_eq!(rt(MsgPackValue::Bool(false)), MsgPackValue::Bool(false));
605    }
606
607    #[test]
608    fn test_positive_fixint() {
609        for i in 0i64..=127 {
610            assert_eq!(rt(MsgPackValue::Int(i)), MsgPackValue::Int(i));
611        }
612    }
613
614    #[test]
615    fn test_negative_fixint() {
616        for i in -32i64..=-1 {
617            assert_eq!(rt(MsgPackValue::Int(i)), MsgPackValue::Int(i));
618        }
619    }
620
621    #[test]
622    fn test_int_ranges() {
623        let vals: &[i64] = &[
624            i8::MIN as i64,
625            i8::MAX as i64,
626            i16::MIN as i64,
627            i16::MAX as i64,
628            i32::MIN as i64,
629            i32::MAX as i64,
630            i64::MIN,
631            i64::MAX,
632        ];
633        for &v in vals {
634            let enc = msgpack_encode(&MsgPackValue::Int(v));
635            let (dec, consumed) = msgpack_decode(&enc).expect("decode");
636            assert_eq!(consumed, enc.len());
637            match dec {
638                MsgPackValue::Int(d) => assert_eq!(d, v),
639                MsgPackValue::UInt(d) => assert_eq!(d as i64, v),
640                other => panic!("unexpected {other:?} for {v}"),
641            }
642        }
643    }
644
645    #[test]
646    fn test_uint_roundtrip() {
647        let vals: &[u64] = &[
648            0,
649            127,
650            128,
651            255,
652            256,
653            65535,
654            65536,
655            u32::MAX as u64,
656            u64::MAX,
657        ];
658        for &v in vals {
659            let enc = msgpack_encode(&MsgPackValue::UInt(v));
660            let (dec, _) = msgpack_decode(&enc).expect("decode");
661            match dec {
662                MsgPackValue::UInt(d) => assert_eq!(d, v),
663                MsgPackValue::Int(d) if d >= 0 => assert_eq!(d as u64, v),
664                other => panic!("unexpected {other:?} for {v}"),
665            }
666        }
667    }
668
669    #[test]
670    fn test_float32_roundtrip() {
671        let v = MsgPackValue::Float32(std::f32::consts::PI);
672        assert_eq!(rt(v), MsgPackValue::Float32(std::f32::consts::PI));
673    }
674
675    #[test]
676    fn test_float64_roundtrip() {
677        let v = MsgPackValue::Float64(std::f64::consts::PI);
678        assert_eq!(rt(v), MsgPackValue::Float64(std::f64::consts::PI));
679    }
680
681    #[test]
682    fn test_str_fixstr() {
683        let s = "hello".to_string();
684        assert_eq!(rt(MsgPackValue::Str(s.clone())), MsgPackValue::Str(s));
685    }
686
687    #[test]
688    fn test_str_str8() {
689        let s = "x".repeat(200);
690        assert_eq!(rt(MsgPackValue::Str(s.clone())), MsgPackValue::Str(s));
691    }
692
693    #[test]
694    fn test_str_str16() {
695        let s = "y".repeat(256);
696        assert_eq!(rt(MsgPackValue::Str(s.clone())), MsgPackValue::Str(s));
697    }
698
699    #[test]
700    fn test_bin_roundtrip() {
701        let b = vec![0u8, 1, 2, 3, 255];
702        assert_eq!(rt(MsgPackValue::Bin(b.clone())), MsgPackValue::Bin(b));
703    }
704
705    #[test]
706    fn test_array_roundtrip() {
707        let arr = MsgPackValue::Array(vec![
708            MsgPackValue::Int(1),
709            MsgPackValue::Str("hello".into()),
710            MsgPackValue::Nil,
711        ]);
712        assert_eq!(rt(arr.clone()), arr);
713    }
714
715    #[test]
716    fn test_map_roundtrip() {
717        let map = MsgPackValue::Map(vec![(
718            MsgPackValue::Str("key".into()),
719            MsgPackValue::Int(99),
720        )]);
721        assert_eq!(rt(map.clone()), map);
722    }
723
724    #[test]
725    fn test_ext_fixext1() {
726        let v = MsgPackValue::Ext(7, vec![0xab]);
727        assert_eq!(rt(v.clone()), v);
728    }
729
730    #[test]
731    fn test_ext_fixext8() {
732        let v = MsgPackValue::Ext(-1, vec![0u8; 8]);
733        assert_eq!(rt(v.clone()), v);
734    }
735
736    #[test]
737    fn test_writer_reader_integration() {
738        let mut w = MsgPackWriter::new();
739        w.write_map_header(2);
740        w.write_str("name");
741        w.write_str("Alice");
742        w.write_str("score");
743        w.write_int(100);
744        let bytes = w.into_bytes();
745
746        let mut r = MsgPackReader::new(&bytes);
747        let v = r.read_value().expect("decode");
748        assert!(r.is_empty());
749
750        match v {
751            MsgPackValue::Map(pairs) => {
752                assert_eq!(pairs.len(), 2);
753                assert_eq!(pairs[0].0, MsgPackValue::Str("name".into()));
754                assert_eq!(pairs[0].1, MsgPackValue::Str("Alice".into()));
755                assert_eq!(pairs[1].0, MsgPackValue::Str("score".into()));
756                assert_eq!(pairs[1].1, MsgPackValue::Int(100));
757            }
758            other => panic!("expected map, got {other:?}"),
759        }
760    }
761
762    #[test]
763    fn test_msgpack_decode_returns_consumed() {
764        let mut w = MsgPackWriter::new();
765        w.write_int(42);
766        w.write_nil();
767        let bytes = w.into_bytes();
768
769        // Only consume the first value
770        let (val, consumed) = msgpack_decode(&bytes).expect("decode");
771        assert_eq!(val, MsgPackValue::Int(42));
772        assert_eq!(consumed, 1); // positive fixint is 1 byte
773    }
774}