Skip to main content

messagepack_core/decode/
any.rs

1use crate::{
2    Format,
3    decode::{
4        ArrayDecoder, Decode, DecodeBorrowed, Error, MapDecoder, ReferenceDecoder, ReferenceStr,
5        ReferenceStrDecoder,
6    },
7    io::IoRead,
8};
9
10/// Skip a single MessagePack value from the reader.
11///
12/// This reads and discards one complete value (including nested containers).
13/// Useful when encountering unknown map keys during decoding.
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum Any<'de> {
16    /// Nil
17    Nil,
18    /// true / false
19    Bool(bool),
20    /// positive fixint / uint8
21    U8(u8),
22    /// uint16
23    U16(u16),
24    /// uint32
25    U32(u32),
26    /// uint64
27    U64(u64),
28    /// negative fixint / int8
29    I8(i8),
30    /// int16
31    I16(i16),
32    /// int32
33    I32(i32),
34    /// int64
35    I64(i64),
36    /// float32
37    F32(f32),
38    /// float64
39    F64(f64),
40    /// fixstr / str8 / str16 / str32 (borrowed)
41    StrBorrowed(&'de str),
42    /// fixstr / str8 / str16 / str32 (copied)
43    StrCopied(usize),
44    /// bin8 / bin16 / bin32 (borrowed)
45    BinBorrowed(&'de [u8]),
46    /// bin8 / bin16 / bin32 (copied)
47    BinCopied(usize),
48    /// fixarray / array16 / array32
49    Array(usize),
50    /// fixmap / map16 / map32
51    Map(usize),
52    /// fixext1 / fixext2 / fixext4 / fixext8 / fixext16 / ext8 / ext16 / ext32 (borrowed)
53    ExtBorrowed {
54        /// extension type
55        r#type: i8,
56        /// extension data
57        data: &'de [u8],
58    },
59    /// fixext1 / fixext2 / fixext4 / fixext8 / fixext16 / ext8 / ext16 / ext32 (copied)
60    ExtCopied {
61        /// extension type
62        r#type: i8,
63        /// extension data length
64        len: usize,
65    },
66}
67
68impl<'de> DecodeBorrowed<'de> for Any<'de> {
69    type Value = Self;
70    fn decode_borrowed_with_format<R>(
71        format: Format,
72        reader: &mut R,
73    ) -> Result<<Self as DecodeBorrowed<'de>>::Value, Error<R::Error>>
74    where
75        R: IoRead<'de>,
76    {
77        match format {
78            Format::Nil => Ok(Any::Nil),
79            Format::False | Format::True => bool::decode_with_format(format, reader).map(Any::Bool),
80
81            Format::PositiveFixInt(_) | Format::Uint8 => {
82                u8::decode_with_format(format, reader).map(Any::U8)
83            }
84            Format::Uint16 => u16::decode_with_format(format, reader).map(Any::U16),
85            Format::Uint32 => u32::decode_with_format(format, reader).map(Any::U32),
86            Format::Uint64 => u64::decode_with_format(format, reader).map(Any::U64),
87            Format::NegativeFixInt(_) | Format::Int8 => {
88                i8::decode_with_format(format, reader).map(Any::I8)
89            }
90            Format::Int16 => i16::decode_with_format(format, reader).map(Any::I16),
91            Format::Int32 => i32::decode_with_format(format, reader).map(Any::I32),
92            Format::Int64 => i64::decode_with_format(format, reader).map(Any::I64),
93
94            Format::Float32 => f32::decode_with_format(format, reader).map(Any::F32),
95            Format::Float64 => f64::decode_with_format(format, reader).map(Any::F64),
96
97            Format::FixStr(_) | Format::Str8 | Format::Str16 | Format::Str32 => {
98                ReferenceStrDecoder::decode_with_format(format, reader).map(|s| match s {
99                    ReferenceStr::Borrowed(s) => Any::StrBorrowed(s),
100                    ReferenceStr::Copied(s) => Any::StrCopied(s.len()),
101                })
102            }
103
104            Format::Bin8 | Format::Bin16 | Format::Bin32 => {
105                ReferenceDecoder::decode_with_format(format, reader).map(|b| match b {
106                    crate::io::Reference::Borrowed(items) => Any::BinBorrowed(items),
107                    crate::io::Reference::Copied(items) => Any::BinCopied(items.len()),
108                })
109            }
110
111            Format::FixExt1
112            | Format::FixExt2
113            | Format::FixExt4
114            | Format::FixExt8
115            | Format::FixExt16
116            | Format::Ext8
117            | Format::Ext16
118            | Format::Ext32 => {
119                let (length, r#type) = crate::extension::read_ext_header(format, reader)?;
120                reader
121                    .read_slice(length)
122                    .map_err(Error::Io)
123                    .map(|data| match data {
124                        crate::io::Reference::Borrowed(items) => Any::ExtBorrowed {
125                            r#type,
126                            data: items,
127                        },
128                        crate::io::Reference::Copied(items) => Any::ExtCopied {
129                            r#type,
130                            len: items.len(),
131                        },
132                    })
133            }
134            Format::FixArray(_) | Format::Array16 | Format::Array32 => {
135                ArrayDecoder::<IterCounter, Any>::decode_with_format(format, reader)
136                    .map(|counter| Any::Array(counter.count))
137            }
138
139            Format::FixMap(_) | Format::Map16 | Format::Map32 => {
140                MapDecoder::<IterCounter, Any, Any>::decode_with_format(format, reader)
141                    .map(|counter| Any::Map(counter.count))
142            }
143            Format::NeverUsed => Err(Error::UnexpectedFormat),
144        }
145    }
146}
147
148struct IterCounter {
149    count: usize,
150}
151
152impl<'de> FromIterator<Any<'de>> for IterCounter {
153    fn from_iter<T: IntoIterator<Item = Any<'de>>>(iter: T) -> Self {
154        let count = iter.into_iter().count();
155        Self { count }
156    }
157}
158
159impl<'de> FromIterator<(Any<'de>, Any<'de>)> for IterCounter {
160    fn from_iter<T: IntoIterator<Item = (Any<'de>, Any<'de>)>>(iter: T) -> Self {
161        let count = iter.into_iter().count();
162        Self { count }
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169    use rstest::rstest;
170
171    #[rstest]
172    // Nil
173    #[case(&[0xc0], Any::Nil)]
174    // Bool
175    #[case(&[0xc2], Any::Bool(false))]
176    #[case(&[0xc3], Any::Bool(true))]
177    // Positive FixInt (u8)
178    #[case(&[0x00], Any::U8(0))]
179    #[case(&[0x7f], Any::U8(127))]
180    // Uint8
181    #[case(&[0xcc, 0x80], Any::U8(128))]
182    #[case(&[0xcc, 0xff], Any::U8(255))]
183    // Uint16
184    #[case(&[0xcd, 0x01, 0x00], Any::U16(256))]
185    #[case(&[0xcd, 0xff, 0xff], Any::U16(65535))]
186    // Uint32
187    #[case(&[0xce, 0x00, 0x01, 0x00, 0x00], Any::U32(65536))]
188    // Uint64
189    #[case(&[0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], Any::U64(4294967296))]
190    // Negative FixInt (i8)
191    #[case(&[0xff], Any::I8(-1))]
192    #[case(&[0xe0], Any::I8(-32))]
193    // Int8
194    #[case(&[0xd0, 0xdf], Any::I8(-33))]
195    #[case(&[0xd0, 0x80], Any::I8(-128))]
196    // Int16
197    #[case(&[0xd1, 0xff, 0x00], Any::I16(-256))]
198    #[case(&[0xd1, 0x80, 0x00], Any::I16(-32768))]
199    // Int32
200    #[case(&[0xd2, 0xff, 0xff, 0x00, 0x00], Any::I32(-65536))]
201    // Int64
202    #[case(&[0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00], Any::I64(-4294967296))]
203    // Float32
204    #[case(&[0xca, 0x41, 0x20, 0x00, 0x00], Any::F32(10.0))]
205    // Float64
206    #[case(&[0xcb, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], Any::F64(10.0))]
207    // FixStr (empty)
208    #[case(&[0xa0], Any::StrBorrowed(""))]
209    // FixStr ("hi")
210    #[case(&[0xa2, 0x68, 0x69], Any::StrBorrowed("hi"))]
211    // Str8
212    #[case(&[0xd9, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f], Any::StrBorrowed("hello"))]
213    // Bin8 (empty)
214    #[case(&[0xc4, 0x00], Any::BinBorrowed(&[]))]
215    // Bin8
216    #[case(&[0xc4, 0x03, 0x01, 0x02, 0x03], Any::BinBorrowed(&[1, 2, 3]))]
217    // FixArray (empty)
218    #[case(&[0x90], Any::Array(0))]
219    // FixArray with 2 elements (nil, true)
220    #[case(&[0x92, 0xc0, 0xc3], Any::Array(2))]
221    // FixArray with nested array
222    #[case(&[0x91, 0x91, 0xc0], Any::Array(1))]
223    // FixMap (empty)
224    #[case(&[0x80], Any::Map(0))]
225    // FixMap with 1 pair (fixint 1 => true)
226    #[case(&[0x81, 0x01, 0xc3], Any::Map(1))]
227    // FixExt1
228    #[case(&[0xd4, 0x01, 0xaa], Any::ExtBorrowed { r#type: 1, data: &[0xaa] })]
229    // FixExt2
230    #[case(&[0xd5, 0x02, 0xaa, 0xbb], Any::ExtBorrowed { r#type: 2, data: &[0xaa, 0xbb] })]
231    // FixExt4
232    #[case(&[0xd6, 0x03, 0x01, 0x02, 0x03, 0x04], Any::ExtBorrowed { r#type: 3, data: &[1, 2, 3, 4] })]
233    // Ext8 (0-length)
234    #[case(&[0xc7, 0x00, 0x05], Any::ExtBorrowed { r#type: 5, data: &[] })]
235    // Ext8
236    #[case(&[0xc7, 0x03, 0x0a, 0x01, 0x02, 0x03], Any::ExtBorrowed { r#type: 10, data: &[1, 2, 3] })]
237    // NeverUsed
238    fn decode_any_ok(#[case] input: &[u8], #[case] expected: Any<'_>) {
239        let mut reader = crate::io::SliceReader::new(input);
240        let value = Any::decode(&mut reader).unwrap();
241        assert_eq!(value, expected);
242    }
243    #[rstest]
244    #[case::never_used(&[0xc1])]
245    fn decode_any_err(#[case] input: &[u8]) {
246        let mut reader = crate::io::SliceReader::new(input);
247        assert!(Any::decode(&mut reader).is_err());
248    }
249}