messagepack_core/extension/
decode.rs

1use super::{ExtensionRef, FixedExtension, read_ext_header};
2use crate::Format;
3use crate::decode::{DecodeBorrowed, Error as DecodeError};
4use crate::io::IoRead;
5
6impl<'de> DecodeBorrowed<'de> for ExtensionRef<'de> {
7    type Value = ExtensionRef<'de>;
8
9    fn decode_borrowed_with_format<R>(
10        format: Format,
11        reader: &mut R,
12    ) -> core::result::Result<Self::Value, DecodeError<R::Error>>
13    where
14        R: IoRead<'de>,
15    {
16        let (len, ext_type) = read_ext_header(format, reader)?;
17
18        let data_ref = reader.read_slice(len).map_err(DecodeError::Io)?;
19        let data = match data_ref {
20            crate::io::Reference::Borrowed(b) => b,
21            crate::io::Reference::Copied(_) => return Err(DecodeError::InvalidData),
22        };
23        Ok(ExtensionRef {
24            r#type: ext_type,
25            data,
26        })
27    }
28}
29
30impl<'de, const N: usize> DecodeBorrowed<'de> for FixedExtension<N> {
31    type Value = FixedExtension<N>;
32
33    fn decode_borrowed_with_format<R>(
34        format: Format,
35        reader: &mut R,
36    ) -> core::result::Result<Self::Value, DecodeError<R::Error>>
37    where
38        R: IoRead<'de>,
39    {
40        let (len, ext_type) = read_ext_header(format, reader)?;
41
42        if len > N {
43            return Err(DecodeError::InvalidData);
44        }
45
46        let payload = reader.read_slice(len).map_err(DecodeError::Io)?;
47        let bytes = payload.as_bytes();
48        if bytes.len() != len {
49            return Err(DecodeError::UnexpectedEof);
50        }
51
52        let mut data = [0u8; N];
53        data[..len].copy_from_slice(bytes);
54
55        Ok(FixedExtension {
56            r#type: ext_type,
57            len,
58            data,
59        })
60    }
61}
62
63#[cfg(feature = "alloc")]
64impl<'de> DecodeBorrowed<'de> for super::owned::ExtensionOwned {
65    type Value = super::owned::ExtensionOwned;
66
67    fn decode_borrowed_with_format<R>(
68        format: Format,
69        reader: &mut R,
70    ) -> core::result::Result<Self::Value, DecodeError<R::Error>>
71    where
72        R: crate::io::IoRead<'de>,
73    {
74        let (len, ext_type) = read_ext_header(format, reader)?;
75
76        let payload = reader.read_slice(len).map_err(DecodeError::Io)?;
77        let data = payload.as_bytes().to_vec();
78
79        Ok(super::owned::ExtensionOwned {
80            r#type: ext_type,
81            data,
82        })
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::decode::Decode;
90    use crate::encode::Encode;
91
92    #[rstest::rstest]
93    #[case(crate::Format::FixExt1.as_byte(),  5_i8, [0x12])]
94    #[case(crate::Format::FixExt2.as_byte(), -1_i8, [0x34, 0x56])]
95    #[case(crate::Format::FixExt4.as_byte(), 42_i8, [0xde, 0xad, 0xbe, 0xef])]
96    #[case(crate::Format::FixExt8.as_byte(), -7_i8, [0xAA; 8])]
97    #[case(crate::Format::FixExt16.as_byte(), 7_i8, [0x55; 16])]
98    fn decode_ext_fixed<E: AsRef<[u8]>>(#[case] marker: u8, #[case] ty: i8, #[case] data: E) {
99        // Buffer: [FixExtN marker][type][data..]
100        let buf = core::iter::once(marker)
101            .chain(core::iter::once(ty as u8))
102            .chain(data.as_ref().iter().cloned())
103            .collect::<Vec<u8>>();
104
105        let mut r = crate::io::SliceReader::new(&buf);
106        let ext = ExtensionRef::decode(&mut r).unwrap();
107        assert_eq!(ext.r#type, ty);
108        assert_eq!(ext.data, data.as_ref());
109        assert!(r.rest().is_empty());
110    }
111
112    #[rstest::rstest]
113    #[case(crate::Format::Ext8, 42_i8, 5u8.to_be_bytes(), [0x11;5])] // small: Ext8
114    #[case(crate::Format::Ext16, -7_i8,   300u16.to_be_bytes(), [0xAA;300])] // medium: Ext16 (>255)
115    #[case(crate::Format::Ext32, 7_i8, 70000u32.to_be_bytes(), [0x55;70000])] // large: Ext32 (>65535)
116    fn decode_ext_sized<S: AsRef<[u8]>, D: AsRef<[u8]>>(
117        #[case] format: crate::Format,
118        #[case] ty: i8,
119        #[case] size: S,
120        #[case] data: D,
121    ) {
122        // MessagePack ext variable-length layout: [format][length][type][data]
123        let buf = format
124            .as_slice()
125            .iter()
126            .chain(size.as_ref())
127            .chain(ty.to_be_bytes().iter())
128            .chain(data.as_ref())
129            .cloned()
130            .collect::<Vec<_>>();
131
132        let mut r = crate::io::SliceReader::new(&buf);
133        let ext = ExtensionRef::decode(&mut r).unwrap();
134        assert_eq!(ext.r#type, ty);
135        assert_eq!(ext.data, data.as_ref());
136        assert!(r.rest().is_empty());
137    }
138
139    #[rstest::rstest]
140    fn fixed_extension_roundtrip() {
141        let data = [1u8, 2, 3, 4];
142        let ext = FixedExtension::<8>::new(5, &data).unwrap();
143        let mut buf = vec![];
144        ext.encode(&mut buf).unwrap();
145        let mut r = crate::io::SliceReader::new(&buf);
146        let decoded = FixedExtension::<8>::decode(&mut r).unwrap();
147        assert_eq!(decoded.r#type, 5);
148        assert_eq!(decoded.as_slice(), &data);
149        assert!(r.rest().is_empty());
150    }
151
152    #[cfg(feature = "std")]
153    #[rstest::rstest]
154    fn fixed_extension_decode_with_std_reader_copied() {
155        // Build Ext8 with len=5, type=7, payload=[9;5]
156        let mut buf = vec![];
157        buf.extend_from_slice(&[crate::Format::Ext8.as_byte(), 5u8, 7u8]);
158        buf.extend_from_slice(&[9u8; 5]);
159
160        // Use StdReader which yields Copied references internally
161        let cursor = std::io::Cursor::new(buf);
162        let mut r = crate::io::StdReader::new(cursor);
163
164        let decoded = FixedExtension::<8>::decode(&mut r).unwrap();
165        assert_eq!(decoded.r#type, 7);
166        assert_eq!(decoded.as_slice(), &[9u8; 5]);
167    }
168
169    #[cfg(feature = "std")]
170    #[rstest::rstest]
171    fn extension_owned_decode_with_std_reader_copied() {
172        // Build Ext8 with len=3, type=-5, payload=[0xAA, 0xBB, 0xCC]
173        let mut buf = vec![];
174        buf.extend_from_slice(&[crate::Format::Ext8.as_byte(), 3u8, (!5u8) + 1]); // 251 -> -5
175        buf.extend_from_slice(&[0xAA, 0xBB, 0xCC]);
176
177        let cursor = std::io::Cursor::new(buf);
178        let mut r = crate::io::StdReader::new(cursor);
179
180        let ext = super::super::ExtensionOwned::decode(&mut r).unwrap();
181        assert_eq!(ext.r#type, -5);
182        assert_eq!(ext.data, vec![0xAA, 0xBB, 0xCC]);
183    }
184}