Skip to main content

scirs2_io/
msgpack.rs

1//! Pure Rust MessagePack serialization and deserialization
2//!
3//! Implements the full [MessagePack specification](https://msgpack.org/index.html)
4//! in pure Rust without any external msgpack crate.  The central type is
5//! [`MsgpackValue`], a recursive enum that can represent any MessagePack value.
6//!
7//! ## Supported formats
8//!
9//! - **fixint** (0 .. 127, -32 .. -1)
10//! - **uint8 / uint16 / uint32 / uint64**
11//! - **int8 / int16 / int32 / int64**
12//! - **float32 / float64**
13//! - **fixstr / str8 / str16 / str32**
14//! - **bin8 / bin16 / bin32**
15//! - **fixarray / array16 / array32**
16//! - **fixmap / map16 / map32**
17//! - **nil / true / false**
18//! - **ext8 / ext16 / ext32 / fixext 1/2/4/8/16**
19//!
20//! ## Serde bridge
21//!
22//! [`to_msgpack`] and [`from_msgpack`] provide a bridge to serde-compatible
23//! types by going through [`serde_json::Value`] as an intermediate
24//! representation (JSON ↔ MsgpackValue).
25//!
26//! ## Examples
27//!
28//! ```rust
29//! use scirs2_io::msgpack::{MsgpackValue, encode, decode};
30//!
31//! let value = MsgpackValue::Map(vec![
32//!     (MsgpackValue::Str("key".into()), MsgpackValue::Int(42)),
33//! ]);
34//! let bytes = encode(&value);
35//! let decoded = decode(&bytes).expect("decode ok");
36//! assert_eq!(value, decoded);
37//! ```
38
39use std::io::{Cursor, Read, Write};
40
41use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
42use serde::{de::DeserializeOwned, Serialize};
43
44use crate::error::{IoError, Result};
45
46// ─────────────────────────────── Format byte constants ───────────────────────
47
48// nil
49const NIL: u8 = 0xc0;
50
51// bool
52const FALSE: u8 = 0xc2;
53const TRUE: u8 = 0xc3;
54
55// float
56const FLOAT32: u8 = 0xca;
57const FLOAT64: u8 = 0xcb;
58
59// unsigned int
60const UINT8: u8 = 0xcc;
61const UINT16: u8 = 0xcd;
62const UINT32: u8 = 0xce;
63const UINT64: u8 = 0xcf;
64
65// signed int
66const INT8: u8 = 0xd0;
67const INT16: u8 = 0xd1;
68const INT32: u8 = 0xd2;
69const INT64: u8 = 0xd3;
70
71// fixext
72const FIXEXT1: u8 = 0xd4;
73const FIXEXT2: u8 = 0xd5;
74const FIXEXT4: u8 = 0xd6;
75const FIXEXT8: u8 = 0xd7;
76const FIXEXT16: u8 = 0xd8;
77
78// str
79const STR8: u8 = 0xd9;
80const STR16: u8 = 0xda;
81const STR32: u8 = 0xdb;
82
83// array
84const ARRAY16: u8 = 0xdc;
85const ARRAY32: u8 = 0xdd;
86
87// map
88const MAP16: u8 = 0xde;
89const MAP32: u8 = 0xdf;
90
91// bin
92const BIN8: u8 = 0xc4;
93const BIN16: u8 = 0xc5;
94const BIN32: u8 = 0xc6;
95
96// ext
97const EXT8: u8 = 0xc7;
98const EXT16: u8 = 0xc8;
99const EXT32: u8 = 0xc9;
100
101// mask / prefix ranges
102const FIXINT_POS_MASK: u8 = 0x7f; // 0xxxxxxx  →  0..127
103const FIXINT_NEG_MASK: u8 = 0xe0; // 111xxxxx  →  -32..-1
104const FIXSTR_MASK: u8 = 0xa0; // 101xxxxx  →  0..31 byte str
105const FIXARRAY_MASK: u8 = 0x90; // 1001xxxx  →  0..15 element array
106const FIXMAP_MASK: u8 = 0x80; // 1000xxxx  →  0..15 entry map
107
108// ─────────────────────────────── Core value type ─────────────────────────────
109
110/// A MessagePack value.
111///
112/// Covers every type defined in the MessagePack specification.
113#[derive(Debug, Clone, PartialEq)]
114pub enum MsgpackValue {
115    /// MessagePack nil
116    Nil,
117    /// Boolean
118    Bool(bool),
119    /// Signed 64-bit integer (covers all msgpack integer widths)
120    Int(i64),
121    /// Unsigned 64-bit integer (for values that do not fit in i64)
122    UInt(u64),
123    /// IEEE 754 double-precision float
124    Float(f64),
125    /// UTF-8 string
126    Str(String),
127    /// Raw binary data
128    Bin(Vec<u8>),
129    /// Heterogeneous array
130    Array(Vec<MsgpackValue>),
131    /// Map (ordered list of key–value pairs; keys are arbitrary MsgpackValues)
132    Map(Vec<(MsgpackValue, MsgpackValue)>),
133    /// Extension type: (type_code, data)
134    Ext(i8, Vec<u8>),
135}
136
137// ─────────────────────────────── Encoder ─────────────────────────────────────
138
139/// Serialize `value` to a MessagePack byte vector.
140pub fn encode(value: &MsgpackValue) -> Vec<u8> {
141    let mut buf = Vec::new();
142    // encode_to always succeeds when writing to a Vec
143    let _ = encode_to(&mut buf, value);
144    buf
145}
146
147/// Serialize `value` to `writer`.
148///
149/// Returns the number of bytes written.
150pub fn write_msgpack(writer: &mut dyn Write, value: &MsgpackValue) -> Result<usize> {
151    encode_to(writer, value)
152}
153
154fn encode_to(w: &mut dyn Write, value: &MsgpackValue) -> Result<usize> {
155    match value {
156        MsgpackValue::Nil => {
157            w.write_u8(NIL).map_err(IoError::Io)?;
158            Ok(1)
159        }
160        MsgpackValue::Bool(b) => {
161            w.write_u8(if *b { TRUE } else { FALSE })
162                .map_err(IoError::Io)?;
163            Ok(1)
164        }
165        MsgpackValue::Int(i) => encode_int(w, *i),
166        MsgpackValue::UInt(u) => encode_uint(w, *u),
167        MsgpackValue::Float(f) => {
168            w.write_u8(FLOAT64).map_err(IoError::Io)?;
169            w.write_f64::<BigEndian>(*f).map_err(IoError::Io)?;
170            Ok(9)
171        }
172        MsgpackValue::Str(s) => encode_str(w, s),
173        MsgpackValue::Bin(b) => encode_bin(w, b),
174        MsgpackValue::Array(items) => encode_array(w, items),
175        MsgpackValue::Map(entries) => encode_map(w, entries),
176        MsgpackValue::Ext(type_code, data) => encode_ext(w, *type_code, data),
177    }
178}
179
180fn encode_int(w: &mut dyn Write, i: i64) -> Result<usize> {
181    // positive fixint
182    if (0..=127).contains(&i) {
183        w.write_u8(i as u8).map_err(IoError::Io)?;
184        return Ok(1);
185    }
186    // negative fixint
187    if (-32..0).contains(&i) {
188        w.write_u8(i as i8 as u8).map_err(IoError::Io)?;
189        return Ok(1);
190    }
191    if i >= i8::MIN as i64 && i <= i8::MAX as i64 {
192        w.write_u8(INT8).map_err(IoError::Io)?;
193        w.write_i8(i as i8).map_err(IoError::Io)?;
194        return Ok(2);
195    }
196    if i >= i16::MIN as i64 && i <= i16::MAX as i64 {
197        w.write_u8(INT16).map_err(IoError::Io)?;
198        w.write_i16::<BigEndian>(i as i16).map_err(IoError::Io)?;
199        return Ok(3);
200    }
201    if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
202        w.write_u8(INT32).map_err(IoError::Io)?;
203        w.write_i32::<BigEndian>(i as i32).map_err(IoError::Io)?;
204        return Ok(5);
205    }
206    w.write_u8(INT64).map_err(IoError::Io)?;
207    w.write_i64::<BigEndian>(i).map_err(IoError::Io)?;
208    Ok(9)
209}
210
211fn encode_uint(w: &mut dyn Write, u: u64) -> Result<usize> {
212    if u <= 127 {
213        w.write_u8(u as u8).map_err(IoError::Io)?;
214        return Ok(1);
215    }
216    if u <= u8::MAX as u64 {
217        w.write_u8(UINT8).map_err(IoError::Io)?;
218        w.write_u8(u as u8).map_err(IoError::Io)?;
219        return Ok(2);
220    }
221    if u <= u16::MAX as u64 {
222        w.write_u8(UINT16).map_err(IoError::Io)?;
223        w.write_u16::<BigEndian>(u as u16).map_err(IoError::Io)?;
224        return Ok(3);
225    }
226    if u <= u32::MAX as u64 {
227        w.write_u8(UINT32).map_err(IoError::Io)?;
228        w.write_u32::<BigEndian>(u as u32).map_err(IoError::Io)?;
229        return Ok(5);
230    }
231    w.write_u8(UINT64).map_err(IoError::Io)?;
232    w.write_u64::<BigEndian>(u).map_err(IoError::Io)?;
233    Ok(9)
234}
235
236fn encode_str(w: &mut dyn Write, s: &str) -> Result<usize> {
237    let bytes = s.as_bytes();
238    let len = bytes.len();
239    let header_size = if len <= 31 {
240        w.write_u8(FIXSTR_MASK | len as u8).map_err(IoError::Io)?;
241        1
242    } else if len <= u8::MAX as usize {
243        w.write_u8(STR8).map_err(IoError::Io)?;
244        w.write_u8(len as u8).map_err(IoError::Io)?;
245        2
246    } else if len <= u16::MAX as usize {
247        w.write_u8(STR16).map_err(IoError::Io)?;
248        w.write_u16::<BigEndian>(len as u16).map_err(IoError::Io)?;
249        3
250    } else if len <= u32::MAX as usize {
251        w.write_u8(STR32).map_err(IoError::Io)?;
252        w.write_u32::<BigEndian>(len as u32).map_err(IoError::Io)?;
253        5
254    } else {
255        return Err(IoError::SerializationError(
256            "string too large for MessagePack (> 4 GiB)".to_string(),
257        ));
258    };
259    w.write_all(bytes).map_err(IoError::Io)?;
260    Ok(header_size + len)
261}
262
263fn encode_bin(w: &mut dyn Write, data: &[u8]) -> Result<usize> {
264    let len = data.len();
265    let header_size = if len <= u8::MAX as usize {
266        w.write_u8(BIN8).map_err(IoError::Io)?;
267        w.write_u8(len as u8).map_err(IoError::Io)?;
268        2
269    } else if len <= u16::MAX as usize {
270        w.write_u8(BIN16).map_err(IoError::Io)?;
271        w.write_u16::<BigEndian>(len as u16).map_err(IoError::Io)?;
272        3
273    } else if len <= u32::MAX as usize {
274        w.write_u8(BIN32).map_err(IoError::Io)?;
275        w.write_u32::<BigEndian>(len as u32).map_err(IoError::Io)?;
276        5
277    } else {
278        return Err(IoError::SerializationError(
279            "binary data too large for MessagePack (> 4 GiB)".to_string(),
280        ));
281    };
282    w.write_all(data).map_err(IoError::Io)?;
283    Ok(header_size + len)
284}
285
286fn encode_array(w: &mut dyn Write, items: &[MsgpackValue]) -> Result<usize> {
287    let n = items.len();
288    let header_size = if n <= 15 {
289        w.write_u8(FIXARRAY_MASK | n as u8).map_err(IoError::Io)?;
290        1
291    } else if n <= u16::MAX as usize {
292        w.write_u8(ARRAY16).map_err(IoError::Io)?;
293        w.write_u16::<BigEndian>(n as u16).map_err(IoError::Io)?;
294        3
295    } else if n <= u32::MAX as usize {
296        w.write_u8(ARRAY32).map_err(IoError::Io)?;
297        w.write_u32::<BigEndian>(n as u32).map_err(IoError::Io)?;
298        5
299    } else {
300        return Err(IoError::SerializationError(
301            "array too large for MessagePack (> 4 GiB elements)".to_string(),
302        ));
303    };
304    let mut total = header_size;
305    for item in items {
306        total += encode_to(w, item)?;
307    }
308    Ok(total)
309}
310
311fn encode_map(w: &mut dyn Write, entries: &[(MsgpackValue, MsgpackValue)]) -> Result<usize> {
312    let n = entries.len();
313    let header_size = if n <= 15 {
314        w.write_u8(FIXMAP_MASK | n as u8).map_err(IoError::Io)?;
315        1
316    } else if n <= u16::MAX as usize {
317        w.write_u8(MAP16).map_err(IoError::Io)?;
318        w.write_u16::<BigEndian>(n as u16).map_err(IoError::Io)?;
319        3
320    } else if n <= u32::MAX as usize {
321        w.write_u8(MAP32).map_err(IoError::Io)?;
322        w.write_u32::<BigEndian>(n as u32).map_err(IoError::Io)?;
323        5
324    } else {
325        return Err(IoError::SerializationError(
326            "map too large for MessagePack (> 4 GiB entries)".to_string(),
327        ));
328    };
329    let mut total = header_size;
330    for (k, v) in entries {
331        total += encode_to(w, k)?;
332        total += encode_to(w, v)?;
333    }
334    Ok(total)
335}
336
337fn encode_ext(w: &mut dyn Write, type_code: i8, data: &[u8]) -> Result<usize> {
338    let len = data.len();
339    let header_size = match len {
340        1 => {
341            w.write_u8(FIXEXT1).map_err(IoError::Io)?;
342            w.write_i8(type_code).map_err(IoError::Io)?;
343            2
344        }
345        2 => {
346            w.write_u8(FIXEXT2).map_err(IoError::Io)?;
347            w.write_i8(type_code).map_err(IoError::Io)?;
348            2
349        }
350        4 => {
351            w.write_u8(FIXEXT4).map_err(IoError::Io)?;
352            w.write_i8(type_code).map_err(IoError::Io)?;
353            2
354        }
355        8 => {
356            w.write_u8(FIXEXT8).map_err(IoError::Io)?;
357            w.write_i8(type_code).map_err(IoError::Io)?;
358            2
359        }
360        16 => {
361            w.write_u8(FIXEXT16).map_err(IoError::Io)?;
362            w.write_i8(type_code).map_err(IoError::Io)?;
363            2
364        }
365        l if l <= u8::MAX as usize => {
366            w.write_u8(EXT8).map_err(IoError::Io)?;
367            w.write_u8(l as u8).map_err(IoError::Io)?;
368            w.write_i8(type_code).map_err(IoError::Io)?;
369            3
370        }
371        l if l <= u16::MAX as usize => {
372            w.write_u8(EXT16).map_err(IoError::Io)?;
373            w.write_u16::<BigEndian>(l as u16).map_err(IoError::Io)?;
374            w.write_i8(type_code).map_err(IoError::Io)?;
375            4
376        }
377        l if l <= u32::MAX as usize => {
378            w.write_u8(EXT32).map_err(IoError::Io)?;
379            w.write_u32::<BigEndian>(l as u32).map_err(IoError::Io)?;
380            w.write_i8(type_code).map_err(IoError::Io)?;
381            6
382        }
383        _ => {
384            return Err(IoError::SerializationError(
385                "ext data too large for MessagePack (> 4 GiB)".to_string(),
386            ));
387        }
388    };
389    w.write_all(data).map_err(IoError::Io)?;
390    Ok(header_size + len)
391}
392
393// ─────────────────────────────── Decoder ─────────────────────────────────────
394
395/// Deserialize a [`MsgpackValue`] from a byte slice.
396///
397/// Returns an error if the bytes are truncated or contain an unknown format byte.
398pub fn decode(bytes: &[u8]) -> Result<MsgpackValue> {
399    let mut cursor = Cursor::new(bytes);
400    let value = decode_from(&mut cursor)?;
401    Ok(value)
402}
403
404/// Deserialize a [`MsgpackValue`] from `reader`.
405pub fn read_msgpack(reader: &mut dyn Read) -> Result<MsgpackValue> {
406    let mut buf = Vec::new();
407    reader.read_to_end(&mut buf).map_err(IoError::Io)?;
408    decode(&buf)
409}
410
411fn decode_from(cur: &mut Cursor<&[u8]>) -> Result<MsgpackValue> {
412    let byte = read_byte(cur)?;
413
414    match byte {
415        // nil
416        NIL => Ok(MsgpackValue::Nil),
417
418        // bool
419        FALSE => Ok(MsgpackValue::Bool(false)),
420        TRUE => Ok(MsgpackValue::Bool(true)),
421
422        // float
423        FLOAT32 => {
424            let f = cur
425                .read_f32::<BigEndian>()
426                .map_err(|e| IoError::FormatError(format!("msgpack float32 read: {e}")))?;
427            Ok(MsgpackValue::Float(f as f64))
428        }
429        FLOAT64 => {
430            let f = cur
431                .read_f64::<BigEndian>()
432                .map_err(|e| IoError::FormatError(format!("msgpack float64 read: {e}")))?;
433            Ok(MsgpackValue::Float(f))
434        }
435
436        // unsigned int
437        UINT8 => {
438            let v = read_byte(cur)? as u64;
439            Ok(MsgpackValue::UInt(v))
440        }
441        UINT16 => {
442            let v = cur
443                .read_u16::<BigEndian>()
444                .map_err(|e| IoError::FormatError(format!("msgpack uint16 read: {e}")))?
445                as u64;
446            Ok(MsgpackValue::UInt(v))
447        }
448        UINT32 => {
449            let v = cur
450                .read_u32::<BigEndian>()
451                .map_err(|e| IoError::FormatError(format!("msgpack uint32 read: {e}")))?
452                as u64;
453            Ok(MsgpackValue::UInt(v))
454        }
455        UINT64 => {
456            let v = cur
457                .read_u64::<BigEndian>()
458                .map_err(|e| IoError::FormatError(format!("msgpack uint64 read: {e}")))?;
459            Ok(MsgpackValue::UInt(v))
460        }
461
462        // signed int
463        INT8 => {
464            let v = cur
465                .read_i8()
466                .map_err(|e| IoError::FormatError(format!("msgpack int8 read: {e}")))?
467                as i64;
468            Ok(MsgpackValue::Int(v))
469        }
470        INT16 => {
471            let v = cur
472                .read_i16::<BigEndian>()
473                .map_err(|e| IoError::FormatError(format!("msgpack int16 read: {e}")))?
474                as i64;
475            Ok(MsgpackValue::Int(v))
476        }
477        INT32 => {
478            let v = cur
479                .read_i32::<BigEndian>()
480                .map_err(|e| IoError::FormatError(format!("msgpack int32 read: {e}")))?
481                as i64;
482            Ok(MsgpackValue::Int(v))
483        }
484        INT64 => {
485            let v = cur
486                .read_i64::<BigEndian>()
487                .map_err(|e| IoError::FormatError(format!("msgpack int64 read: {e}")))?;
488            Ok(MsgpackValue::Int(v))
489        }
490
491        // str8 / str16 / str32
492        STR8 => {
493            let len = read_byte(cur)? as usize;
494            Ok(MsgpackValue::Str(read_utf8(cur, len)?))
495        }
496        STR16 => {
497            let len = cur
498                .read_u16::<BigEndian>()
499                .map_err(|e| IoError::FormatError(format!("msgpack str16 len: {e}")))?
500                as usize;
501            Ok(MsgpackValue::Str(read_utf8(cur, len)?))
502        }
503        STR32 => {
504            let len = cur
505                .read_u32::<BigEndian>()
506                .map_err(|e| IoError::FormatError(format!("msgpack str32 len: {e}")))?
507                as usize;
508            Ok(MsgpackValue::Str(read_utf8(cur, len)?))
509        }
510
511        // bin8 / bin16 / bin32
512        BIN8 => {
513            let len = read_byte(cur)? as usize;
514            Ok(MsgpackValue::Bin(read_bytes(cur, len)?))
515        }
516        BIN16 => {
517            let len = cur
518                .read_u16::<BigEndian>()
519                .map_err(|e| IoError::FormatError(format!("msgpack bin16 len: {e}")))?
520                as usize;
521            Ok(MsgpackValue::Bin(read_bytes(cur, len)?))
522        }
523        BIN32 => {
524            let len = cur
525                .read_u32::<BigEndian>()
526                .map_err(|e| IoError::FormatError(format!("msgpack bin32 len: {e}")))?
527                as usize;
528            Ok(MsgpackValue::Bin(read_bytes(cur, len)?))
529        }
530
531        // array16 / array32
532        ARRAY16 => {
533            let n = cur
534                .read_u16::<BigEndian>()
535                .map_err(|e| IoError::FormatError(format!("msgpack array16 len: {e}")))?
536                as usize;
537            read_array(cur, n)
538        }
539        ARRAY32 => {
540            let n = cur
541                .read_u32::<BigEndian>()
542                .map_err(|e| IoError::FormatError(format!("msgpack array32 len: {e}")))?
543                as usize;
544            read_array(cur, n)
545        }
546
547        // map16 / map32
548        MAP16 => {
549            let n = cur
550                .read_u16::<BigEndian>()
551                .map_err(|e| IoError::FormatError(format!("msgpack map16 len: {e}")))?
552                as usize;
553            read_map(cur, n)
554        }
555        MAP32 => {
556            let n = cur
557                .read_u32::<BigEndian>()
558                .map_err(|e| IoError::FormatError(format!("msgpack map32 len: {e}")))?
559                as usize;
560            read_map(cur, n)
561        }
562
563        // fixext
564        FIXEXT1 => {
565            let tc = cur
566                .read_i8()
567                .map_err(|e| IoError::FormatError(format!("msgpack fixext1 type: {e}")))?;
568            Ok(MsgpackValue::Ext(tc, read_bytes(cur, 1)?))
569        }
570        FIXEXT2 => {
571            let tc = cur
572                .read_i8()
573                .map_err(|e| IoError::FormatError(format!("msgpack fixext2 type: {e}")))?;
574            Ok(MsgpackValue::Ext(tc, read_bytes(cur, 2)?))
575        }
576        FIXEXT4 => {
577            let tc = cur
578                .read_i8()
579                .map_err(|e| IoError::FormatError(format!("msgpack fixext4 type: {e}")))?;
580            Ok(MsgpackValue::Ext(tc, read_bytes(cur, 4)?))
581        }
582        FIXEXT8 => {
583            let tc = cur
584                .read_i8()
585                .map_err(|e| IoError::FormatError(format!("msgpack fixext8 type: {e}")))?;
586            Ok(MsgpackValue::Ext(tc, read_bytes(cur, 8)?))
587        }
588        FIXEXT16 => {
589            let tc = cur
590                .read_i8()
591                .map_err(|e| IoError::FormatError(format!("msgpack fixext16 type: {e}")))?;
592            Ok(MsgpackValue::Ext(tc, read_bytes(cur, 16)?))
593        }
594
595        // ext8 / ext16 / ext32
596        EXT8 => {
597            let len = read_byte(cur)? as usize;
598            let tc = cur
599                .read_i8()
600                .map_err(|e| IoError::FormatError(format!("msgpack ext8 type: {e}")))?;
601            Ok(MsgpackValue::Ext(tc, read_bytes(cur, len)?))
602        }
603        EXT16 => {
604            let len = cur
605                .read_u16::<BigEndian>()
606                .map_err(|e| IoError::FormatError(format!("msgpack ext16 len: {e}")))?
607                as usize;
608            let tc = cur
609                .read_i8()
610                .map_err(|e| IoError::FormatError(format!("msgpack ext16 type: {e}")))?;
611            Ok(MsgpackValue::Ext(tc, read_bytes(cur, len)?))
612        }
613        EXT32 => {
614            let len = cur
615                .read_u32::<BigEndian>()
616                .map_err(|e| IoError::FormatError(format!("msgpack ext32 len: {e}")))?
617                as usize;
618            let tc = cur
619                .read_i8()
620                .map_err(|e| IoError::FormatError(format!("msgpack ext32 type: {e}")))?;
621            Ok(MsgpackValue::Ext(tc, read_bytes(cur, len)?))
622        }
623
624        // positive fixint (0xxxxxxx)
625        b if b & 0x80 == 0 => Ok(MsgpackValue::Int((b & FIXINT_POS_MASK) as i64)),
626
627        // negative fixint (111xxxxx)
628        b if b & 0xe0 == FIXINT_NEG_MASK => {
629            // sign-extend the 5-bit twos-complement value
630            let signed = (b as i8) as i64;
631            Ok(MsgpackValue::Int(signed))
632        }
633
634        // fixstr (101xxxxx)
635        b if b & 0xe0 == FIXSTR_MASK => {
636            let len = (b & 0x1f) as usize;
637            Ok(MsgpackValue::Str(read_utf8(cur, len)?))
638        }
639
640        // fixarray (1001xxxx)
641        b if b & 0xf0 == FIXARRAY_MASK => {
642            let n = (b & 0x0f) as usize;
643            read_array(cur, n)
644        }
645
646        // fixmap (1000xxxx)
647        b if b & 0xf0 == FIXMAP_MASK => {
648            let n = (b & 0x0f) as usize;
649            read_map(cur, n)
650        }
651
652        // Unused / never-used format bytes
653        other => Err(IoError::FormatError(format!(
654            "unknown MessagePack format byte: {other:#04x}"
655        ))),
656    }
657}
658
659// ─────────────────────────────── Cursor helpers ──────────────────────────────
660
661fn read_byte(cur: &mut Cursor<&[u8]>) -> Result<u8> {
662    cur.read_u8()
663        .map_err(|e| IoError::FormatError(format!("unexpected end of msgpack data: {e}")))
664}
665
666fn read_bytes(cur: &mut Cursor<&[u8]>, len: usize) -> Result<Vec<u8>> {
667    let mut buf = vec![0u8; len];
668    cur.read_exact(&mut buf)
669        .map_err(|e| IoError::FormatError(format!("truncated msgpack data ({len} bytes): {e}")))?;
670    Ok(buf)
671}
672
673fn read_utf8(cur: &mut Cursor<&[u8]>, len: usize) -> Result<String> {
674    let bytes = read_bytes(cur, len)?;
675    String::from_utf8(bytes)
676        .map_err(|e| IoError::FormatError(format!("invalid UTF-8 in msgpack str: {e}")))
677}
678
679fn read_array(cur: &mut Cursor<&[u8]>, n: usize) -> Result<MsgpackValue> {
680    let mut items = Vec::with_capacity(n.min(1024));
681    for _ in 0..n {
682        items.push(decode_from(cur)?);
683    }
684    Ok(MsgpackValue::Array(items))
685}
686
687fn read_map(cur: &mut Cursor<&[u8]>, n: usize) -> Result<MsgpackValue> {
688    let mut entries = Vec::with_capacity(n.min(1024));
689    for _ in 0..n {
690        let k = decode_from(cur)?;
691        let v = decode_from(cur)?;
692        entries.push((k, v));
693    }
694    Ok(MsgpackValue::Map(entries))
695}
696
697// ─────────────────────────────── Serde bridge ────────────────────────────────
698
699/// Serialize any `serde::Serialize` type to MessagePack bytes.
700///
701/// The value is first converted to a [`serde_json::Value`] then encoded with
702/// the pure-Rust MessagePack encoder in this module.
703pub fn to_msgpack<T: Serialize>(value: &T) -> Result<Vec<u8>> {
704    let json_val = serde_json::to_value(value)
705        .map_err(|e| IoError::SerializationError(format!("to_msgpack serde_json: {e}")))?;
706    let mp_val = json_value_to_msgpack(&json_val);
707    Ok(encode(&mp_val))
708}
709
710/// Deserialize any `serde::de::DeserializeOwned` type from MessagePack bytes.
711///
712/// The bytes are decoded to a [`MsgpackValue`], converted to a
713/// [`serde_json::Value`], and then deserialized via serde.
714pub fn from_msgpack<T: DeserializeOwned>(bytes: &[u8]) -> Result<T> {
715    let mp_val = decode(bytes)?;
716    let json_val = msgpack_to_json_value(&mp_val)?;
717    serde_json::from_value(json_val)
718        .map_err(|e| IoError::DeserializationError(format!("from_msgpack serde_json: {e}")))
719}
720
721// ─────────────────────────────── JSON ↔ MsgpackValue ─────────────────────────
722
723/// Convert a [`serde_json::Value`] to a [`MsgpackValue`].
724pub fn json_value_to_msgpack(v: &serde_json::Value) -> MsgpackValue {
725    match v {
726        serde_json::Value::Null => MsgpackValue::Nil,
727        serde_json::Value::Bool(b) => MsgpackValue::Bool(*b),
728        serde_json::Value::Number(n) => {
729            if let Some(i) = n.as_i64() {
730                MsgpackValue::Int(i)
731            } else if let Some(u) = n.as_u64() {
732                MsgpackValue::UInt(u)
733            } else {
734                MsgpackValue::Float(n.as_f64().unwrap_or(f64::NAN))
735            }
736        }
737        serde_json::Value::String(s) => MsgpackValue::Str(s.clone()),
738        serde_json::Value::Array(arr) => {
739            MsgpackValue::Array(arr.iter().map(json_value_to_msgpack).collect())
740        }
741        serde_json::Value::Object(obj) => MsgpackValue::Map(
742            obj.iter()
743                .map(|(k, v)| (MsgpackValue::Str(k.clone()), json_value_to_msgpack(v)))
744                .collect(),
745        ),
746    }
747}
748
749/// Convert a [`MsgpackValue`] to a [`serde_json::Value`].
750///
751/// - Binary data is represented as an array of unsigned integers.
752/// - Extension types are represented as `{"__ext_type": <code>, "data": [bytes]}`.
753/// - UInt values that exceed `i64::MAX` are represented as `f64` (JSON has no
754///   distinct unsigned integer type).
755pub fn msgpack_to_json_value(v: &MsgpackValue) -> Result<serde_json::Value> {
756    match v {
757        MsgpackValue::Nil => Ok(serde_json::Value::Null),
758        MsgpackValue::Bool(b) => Ok(serde_json::Value::Bool(*b)),
759        MsgpackValue::Int(i) => Ok(serde_json::json!(*i)),
760        MsgpackValue::UInt(u) => {
761            if *u <= i64::MAX as u64 {
762                Ok(serde_json::json!(*u as i64))
763            } else {
764                Ok(serde_json::json!(*u as f64))
765            }
766        }
767        MsgpackValue::Float(f) => {
768            let n = serde_json::Number::from_f64(*f).ok_or_else(|| {
769                IoError::ConversionError(format!("non-finite float cannot be JSON: {f}"))
770            })?;
771            Ok(serde_json::Value::Number(n))
772        }
773        MsgpackValue::Str(s) => Ok(serde_json::Value::String(s.clone())),
774        MsgpackValue::Bin(b) => {
775            // Represent binary as array of u8 values
776            let arr: Vec<serde_json::Value> =
777                b.iter().map(|&byte| serde_json::json!(byte)).collect();
778            Ok(serde_json::Value::Array(arr))
779        }
780        MsgpackValue::Array(items) => {
781            let arr: Result<Vec<serde_json::Value>> =
782                items.iter().map(msgpack_to_json_value).collect();
783            Ok(serde_json::Value::Array(arr?))
784        }
785        MsgpackValue::Map(entries) => {
786            let mut obj = serde_json::Map::new();
787            for (k, v) in entries {
788                let key = match k {
789                    MsgpackValue::Str(s) => s.clone(),
790                    other => {
791                        // Non-string keys: convert to their string representation
792                        format!("{other:?}")
793                    }
794                };
795                obj.insert(key, msgpack_to_json_value(v)?);
796            }
797            Ok(serde_json::Value::Object(obj))
798        }
799        MsgpackValue::Ext(type_code, data) => {
800            // Encode as a special JSON object
801            let bytes: Vec<serde_json::Value> =
802                data.iter().map(|&b| serde_json::json!(b)).collect();
803            Ok(serde_json::json!({
804                "__msgpack_ext_type": *type_code as i64,
805                "data": bytes,
806            }))
807        }
808    }
809}
810
811// ─────────────────────────────── Tests ───────────────────────────────────────
812
813#[cfg(test)]
814mod tests {
815    use super::*;
816
817    // ── roundtrip helpers ────────────────────────────────────────────────────
818
819    fn rt(v: &MsgpackValue) -> MsgpackValue {
820        let bytes = encode(v);
821        decode(&bytes).expect("decode")
822    }
823
824    // ── nil / bool ───────────────────────────────────────────────────────────
825
826    #[test]
827    fn test_nil_roundtrip() {
828        assert_eq!(rt(&MsgpackValue::Nil), MsgpackValue::Nil);
829    }
830
831    #[test]
832    fn test_bool_roundtrip() {
833        assert_eq!(rt(&MsgpackValue::Bool(true)), MsgpackValue::Bool(true));
834        assert_eq!(rt(&MsgpackValue::Bool(false)), MsgpackValue::Bool(false));
835    }
836
837    // ── integer: positive fixint ─────────────────────────────────────────────
838
839    #[test]
840    fn test_positive_fixint_boundaries() {
841        for i in [0i64, 1, 63, 127] {
842            let v = MsgpackValue::Int(i);
843            assert_eq!(rt(&v), v, "fixint {i}");
844            // positive fixint is always 1 byte
845            assert_eq!(encode(&v).len(), 1, "fixint len {i}");
846        }
847    }
848
849    // ── integer: negative fixint ─────────────────────────────────────────────
850
851    #[test]
852    fn test_negative_fixint_boundaries() {
853        for i in [-1i64, -16, -32] {
854            let v = MsgpackValue::Int(i);
855            assert_eq!(rt(&v), v, "neg fixint {i}");
856            assert_eq!(encode(&v).len(), 1, "neg fixint len {i}");
857        }
858    }
859
860    // ── integer widths ───────────────────────────────────────────────────────
861
862    #[test]
863    fn test_int8_roundtrip() {
864        for i in [i8::MIN as i64, i8::MAX as i64, -33i64, 128] {
865            let v = MsgpackValue::Int(i);
866            assert_eq!(rt(&v), v, "int8 {i}");
867        }
868    }
869
870    #[test]
871    fn test_int16_roundtrip() {
872        for i in [i16::MIN as i64, i16::MAX as i64, 256i64, -300] {
873            let v = MsgpackValue::Int(i);
874            assert_eq!(rt(&v), v, "int16 {i}");
875        }
876    }
877
878    #[test]
879    fn test_int32_roundtrip() {
880        for i in [i32::MIN as i64, i32::MAX as i64, 70_000i64, -70_000] {
881            let v = MsgpackValue::Int(i);
882            assert_eq!(rt(&v), v, "int32 {i}");
883        }
884    }
885
886    #[test]
887    fn test_int64_roundtrip() {
888        for i in [i64::MIN, i64::MAX, i64::from(i32::MAX) + 1] {
889            let v = MsgpackValue::Int(i);
890            assert_eq!(rt(&v), v, "int64 {i}");
891        }
892    }
893
894    // ── uint widths ──────────────────────────────────────────────────────────
895
896    #[test]
897    fn test_uint8_roundtrip() {
898        let v = MsgpackValue::UInt(200);
899        assert_eq!(rt(&v), v);
900        assert_eq!(encode(&v).len(), 2); // UINT8 + value
901    }
902
903    #[test]
904    fn test_uint16_roundtrip() {
905        let v = MsgpackValue::UInt(1000);
906        assert_eq!(rt(&v), v);
907        assert_eq!(encode(&v).len(), 3);
908    }
909
910    #[test]
911    fn test_uint32_roundtrip() {
912        let v = MsgpackValue::UInt(100_000);
913        assert_eq!(rt(&v), v);
914        assert_eq!(encode(&v).len(), 5);
915    }
916
917    #[test]
918    fn test_uint64_roundtrip() {
919        let v = MsgpackValue::UInt(u64::MAX);
920        assert_eq!(rt(&v), v);
921        assert_eq!(encode(&v).len(), 9);
922    }
923
924    // ── float ────────────────────────────────────────────────────────────────
925
926    #[test]
927    fn test_float64_roundtrip() {
928        for f in [
929            0.0_f64,
930            1.0,
931            -1.0,
932            f64::MAX,
933            f64::MIN_POSITIVE,
934            std::f64::consts::PI,
935        ] {
936            let v = MsgpackValue::Float(f);
937            assert_eq!(rt(&v), v, "float64 {f}");
938        }
939    }
940
941    // ── string ───────────────────────────────────────────────────────────────
942
943    #[test]
944    fn test_fixstr_roundtrip() {
945        let v = MsgpackValue::Str("hello".into());
946        assert_eq!(rt(&v), v);
947        // fixstr: 1 header + 5 bytes
948        assert_eq!(encode(&v).len(), 6);
949    }
950
951    #[test]
952    fn test_str8_roundtrip() {
953        // 32 bytes → needs str8
954        let s: String = "x".repeat(32);
955        let v = MsgpackValue::Str(s.clone());
956        let encoded = encode(&v);
957        assert_eq!(encoded[0], STR8);
958        assert_eq!(rt(&v), v);
959    }
960
961    #[test]
962    fn test_str16_roundtrip() {
963        let s: String = "y".repeat(300);
964        let v = MsgpackValue::Str(s);
965        let encoded = encode(&v);
966        assert_eq!(encoded[0], STR16);
967        assert_eq!(rt(&v), v);
968    }
969
970    #[test]
971    fn test_empty_string() {
972        let v = MsgpackValue::Str(String::new());
973        assert_eq!(rt(&v), v);
974    }
975
976    // ── binary ───────────────────────────────────────────────────────────────
977
978    #[test]
979    fn test_bin8_roundtrip() {
980        let v = MsgpackValue::Bin(vec![0x00, 0xff, 0x42]);
981        assert_eq!(rt(&v), v);
982        assert_eq!(encode(&v)[0], BIN8);
983    }
984
985    #[test]
986    fn test_bin16_roundtrip() {
987        let v = MsgpackValue::Bin(vec![0u8; 256]);
988        let encoded = encode(&v);
989        assert_eq!(encoded[0], BIN16);
990        assert_eq!(rt(&v), v);
991    }
992
993    #[test]
994    fn test_bin32_roundtrip() {
995        let v = MsgpackValue::Bin(vec![1u8; 65536]);
996        let encoded = encode(&v);
997        assert_eq!(encoded[0], BIN32);
998        assert_eq!(rt(&v), v);
999    }
1000
1001    // ── array ────────────────────────────────────────────────────────────────
1002
1003    #[test]
1004    fn test_fixarray_roundtrip() {
1005        let v = MsgpackValue::Array(vec![
1006            MsgpackValue::Int(1),
1007            MsgpackValue::Str("two".into()),
1008            MsgpackValue::Bool(true),
1009        ]);
1010        assert_eq!(rt(&v), v);
1011    }
1012
1013    #[test]
1014    fn test_array16_roundtrip() {
1015        let items: Vec<MsgpackValue> = (0..16).map(|i| MsgpackValue::Int(i)).collect();
1016        let v = MsgpackValue::Array(items);
1017        let encoded = encode(&v);
1018        assert_eq!(encoded[0], ARRAY16);
1019        assert_eq!(rt(&v), v);
1020    }
1021
1022    #[test]
1023    fn test_nested_array() {
1024        let inner = MsgpackValue::Array(vec![MsgpackValue::Int(99)]);
1025        let outer = MsgpackValue::Array(vec![inner, MsgpackValue::Nil]);
1026        assert_eq!(rt(&outer), outer);
1027    }
1028
1029    // ── map ──────────────────────────────────────────────────────────────────
1030
1031    #[test]
1032    fn test_fixmap_roundtrip() {
1033        let v = MsgpackValue::Map(vec![
1034            (MsgpackValue::Str("a".into()), MsgpackValue::Int(1)),
1035            (MsgpackValue::Str("b".into()), MsgpackValue::Bool(false)),
1036        ]);
1037        assert_eq!(rt(&v), v);
1038    }
1039
1040    #[test]
1041    fn test_map16_roundtrip() {
1042        let entries: Vec<(MsgpackValue, MsgpackValue)> = (0..16)
1043            .map(|i| (MsgpackValue::Int(i), MsgpackValue::Int(i * 2)))
1044            .collect();
1045        let v = MsgpackValue::Map(entries);
1046        let encoded = encode(&v);
1047        assert_eq!(encoded[0], MAP16);
1048        assert_eq!(rt(&v), v);
1049    }
1050
1051    // ── ext ──────────────────────────────────────────────────────────────────
1052
1053    #[test]
1054    fn test_fixext1_roundtrip() {
1055        let v = MsgpackValue::Ext(42, vec![0xab]);
1056        assert_eq!(rt(&v), v);
1057        assert_eq!(encode(&v).len(), 3); // FIXEXT1 + type + 1 data
1058    }
1059
1060    #[test]
1061    fn test_fixext8_roundtrip() {
1062        let v = MsgpackValue::Ext(-1, vec![0u8; 8]);
1063        assert_eq!(rt(&v), v);
1064    }
1065
1066    #[test]
1067    fn test_ext8_roundtrip() {
1068        let v = MsgpackValue::Ext(5, vec![0xffu8; 3]);
1069        assert_eq!(rt(&v), v);
1070        assert_eq!(encode(&v)[0], EXT8);
1071    }
1072
1073    // ── serde bridge ─────────────────────────────────────────────────────────
1074
1075    #[test]
1076    fn test_to_from_msgpack_struct() {
1077        #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
1078        struct Point {
1079            x: f64,
1080            y: f64,
1081        }
1082
1083        let p = Point { x: 1.5, y: -2.5 };
1084        let bytes = to_msgpack(&p).expect("serialize");
1085        let p2: Point = from_msgpack(&bytes).expect("deserialize");
1086        assert!((p.x - p2.x).abs() < 1e-10);
1087        assert!((p.y - p2.y).abs() < 1e-10);
1088    }
1089
1090    #[test]
1091    fn test_to_from_msgpack_vec() {
1092        let data = vec![1i64, 2, 3, 4, 5];
1093        let bytes = to_msgpack(&data).expect("serialize");
1094        let out: Vec<i64> = from_msgpack(&bytes).expect("deserialize");
1095        assert_eq!(data, out);
1096    }
1097
1098    // ── write_msgpack / read_msgpack ─────────────────────────────────────────
1099
1100    #[test]
1101    fn test_write_read_msgpack() {
1102        let value = MsgpackValue::Map(vec![
1103            (MsgpackValue::Str("count".into()), MsgpackValue::Int(7)),
1104            (
1105                MsgpackValue::Str("label".into()),
1106                MsgpackValue::Str("test".into()),
1107            ),
1108        ]);
1109
1110        let mut buf = Vec::new();
1111        write_msgpack(&mut buf, &value).expect("write");
1112        let decoded = read_msgpack(&mut buf.as_slice()).expect("read");
1113        assert_eq!(value, decoded);
1114    }
1115
1116    // ── error cases ──────────────────────────────────────────────────────────
1117
1118    #[test]
1119    fn test_decode_empty_input() {
1120        let result = decode(&[]);
1121        assert!(result.is_err(), "empty input should error");
1122    }
1123
1124    #[test]
1125    fn test_decode_truncated_str() {
1126        // fixstr of length 5, but only 3 bytes of data
1127        let mut bytes = Vec::new();
1128        bytes.push(FIXSTR_MASK | 5);
1129        bytes.extend_from_slice(b"abc"); // missing 2 bytes
1130        let result = decode(&bytes);
1131        assert!(result.is_err(), "truncated str should error");
1132    }
1133
1134    #[test]
1135    fn test_decode_unknown_byte() {
1136        // 0xc1 is a never-used format byte in the spec
1137        let result = decode(&[0xc1]);
1138        assert!(result.is_err(), "unknown format byte should error");
1139    }
1140}