messagepack_core/decode/
array.rs

1//! Array decoding helpers.
2
3use core::marker::PhantomData;
4
5use super::{DecodeBorrowed, Error, NbyteReader};
6use crate::{formats::Format, io::IoRead};
7
8/// Decode a MessagePack array of `V` into `Array` collecting iterator.
9pub struct ArrayDecoder<Array, V>(PhantomData<(Array, V)>);
10
11impl<'de, Array, V> DecodeBorrowed<'de> for ArrayDecoder<Array, V>
12where
13    V: DecodeBorrowed<'de>,
14    Array: FromIterator<V::Value>,
15{
16    type Value = Array;
17
18    fn decode_borrowed_with_format<R>(
19        format: Format,
20        reader: &mut R,
21    ) -> core::result::Result<Self::Value, Error<R::Error>>
22    where
23        R: IoRead<'de>,
24    {
25        let len = match format {
26            Format::FixArray(len) => len.into(),
27            Format::Array16 => NbyteReader::<2>::read(reader)?,
28            Format::Array32 => NbyteReader::<4>::read(reader)?,
29            _ => return Err(Error::UnexpectedFormat),
30        };
31
32        let out = (0..len)
33            .map(|_| V::decode_borrowed(reader))
34            .collect::<core::result::Result<Array, Error<R::Error>>>()?;
35        Ok(out)
36    }
37}
38
39impl<'de, const N: usize, V> DecodeBorrowed<'de> for [V; N]
40where
41    V: DecodeBorrowed<'de>,
42{
43    type Value = [V::Value; N];
44
45    fn decode_borrowed_with_format<R>(
46        format: Format,
47        reader: &mut R,
48    ) -> core::result::Result<Self::Value, Error<R::Error>>
49    where
50        R: IoRead<'de>,
51    {
52        let len = match format {
53            Format::FixArray(len) => len.into(),
54            Format::Array16 => NbyteReader::<2>::read(reader)?,
55            Format::Array32 => NbyteReader::<4>::read(reader)?,
56            _ => return Err(Error::UnexpectedFormat),
57        };
58        if len != N {
59            return Err(Error::InvalidData);
60        };
61
62        let mut tmp: [Option<V::Value>; N] = core::array::from_fn(|_| None);
63        for item in tmp.iter_mut() {
64            *item = Some(V::decode_borrowed(reader)?);
65        }
66        // NOTE: This `expect` cannot fire given the invariant established above.
67        // - We allocate a temporary `[Option<V::Value>; N]` initialized to `None`.
68        // - The loop assigns `Some(..)` to every element or returns early on error.
69        // - Therefore, reaching here implies all entries are `Some`, making the
70        //   unwrap logically safe.
71        //
72        // Why not avoid `expect` entirely?
73        // - On stable Rust, there is no fully-ergonomic way to construct
74        //   `[T; N]` from a fallible producer without either allocation or
75        //   `unsafe`.
76        // - `core::array::try_from_fn` would be a perfect fit but is not yet
77        //   stabilized at the time of writing.
78        // - Collecting into `Vec<T>` and converting with `try_into::<[T; N]>()`
79        //   requires the `alloc` feature, while this crate targets `no_std` by
80        //   default.
81        //
82        // If/when `try_from_fn` is stabilized, or if an `alloc`-enabled fast
83        // path is desired, this code can be revisited to remove `expect`.
84        let out = core::array::from_fn(|i| tmp[i].take().expect("initialized"));
85        Ok(out)
86    }
87}
88
89macro_rules! tuple_decode_impls {
90    ($($len:expr => ($($name:ident)+))+ $(,)?) => {
91        $(
92            impl<'de, $($name),+> DecodeBorrowed<'de> for ($($name,)+)
93            where
94                $($name: DecodeBorrowed<'de>,)+
95            {
96                type Value = ($(<$name as DecodeBorrowed<'de>>::Value,)+);
97
98                fn decode_borrowed_with_format<R>(format: Format, reader: &mut R) -> core::result::Result<Self::Value, Error<R::Error>>
99                where
100                    R: IoRead<'de>,
101                {
102                    let len = match format {
103                        Format::FixArray(len) => len.into(),
104                        Format::Array16 => NbyteReader::<2>::read(reader)?,
105                        Format::Array32 => NbyteReader::<4>::read(reader)?,
106                        _ => return Err(Error::UnexpectedFormat),
107                    };
108                    if len != $len {
109                        return Err(Error::InvalidData);
110                    }
111
112                    let value = (
113                        $({
114                            let v = <$name as DecodeBorrowed<'de>>::decode_borrowed(reader)?;
115                            v
116                        },)+
117                    );
118                    Ok(value)
119                }
120            }
121        )+
122    };
123}
124
125tuple_decode_impls! {
126    1  => (V0)
127    2  => (V0 V1)
128    3  => (V0 V1 V2)
129    4  => (V0 V1 V2 V3)
130    5  => (V0 V1 V2 V3 V4)
131    6  => (V0 V1 V2 V3 V4 V5)
132    7  => (V0 V1 V2 V3 V4 V5 V6)
133    8  => (V0 V1 V2 V3 V4 V5 V6 V7)
134    9  => (V0 V1 V2 V3 V4 V5 V6 V7 V8)
135    10 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9)
136    11 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10)
137    12 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11)
138    13 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12)
139    14 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13)
140    15 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14)
141    16 => (V0 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15)
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::decode::Decode;
148    use rstest::rstest;
149
150    #[rstest]
151    #[case(&[0x92, 0x01, 0x02, 0x01], vec![1u8, 2], &[0x01])]
152    #[case(&[0xdc, 0x00, 0x02, 0x2a, 0x2b], vec![42u8, 43], &[])]
153    fn array_decode_success(
154        #[case] buf: &[u8],
155        #[case] expect: Vec<u8>,
156        #[case] rest_expect: &[u8],
157    ) {
158        let mut r = crate::io::SliceReader::new(buf);
159        let decoded = ArrayDecoder::<Vec<u8>, u8>::decode(&mut r).unwrap();
160        assert_eq!(decoded, expect);
161        assert_eq!(r.rest(), rest_expect);
162    }
163
164    #[rstest]
165    fn array_decoder_unexpected_format() {
166        let buf = &[0x81, 0x01, 0x02]; // map(1)
167        let mut r = crate::io::SliceReader::new(buf);
168        let err = ArrayDecoder::<Vec<u8>, u8>::decode(&mut r).unwrap_err();
169        assert!(matches!(err, Error::UnexpectedFormat));
170    }
171
172    #[rstest]
173    fn fixed_array_len0_success() {
174        let buf = &[0x90]; // array(0)
175        let mut r = crate::io::SliceReader::new(buf);
176        let arr = <[u8; 0] as Decode>::decode(&mut r).unwrap();
177        assert_eq!(arr, []);
178        assert!(r.rest().is_empty());
179    }
180
181    #[rstest]
182    fn fixed_array_len3_success() {
183        let buf = &[0x93, 0x0a, 0x0b, 0x0c];
184        let mut r = crate::io::SliceReader::new(buf);
185        let arr = <[u8; 3] as Decode>::decode(&mut r).unwrap();
186        assert_eq!(arr, [10u8, 11, 12]);
187        assert!(r.rest().is_empty());
188    }
189
190    #[rstest]
191    #[case(&[0x92, 0x01, 0x02])] // len=2
192    #[case(&[0x94, 0x01, 0x02, 0x03, 0x04])] // len=4 
193    fn fixed_array_len_mismatch(#[case] buf: &[u8]) {
194        let mut r = crate::io::SliceReader::new(buf);
195        let err = <[u8; 3] as Decode>::decode(&mut r).unwrap_err();
196        assert!(matches!(err, Error::InvalidData));
197    }
198
199    #[rstest]
200    fn tuple1_success() {
201        let buf = &[0x91, 0x2a]; // [42]
202        let mut r = crate::io::SliceReader::new(buf);
203        let (v0,) = <(u8,) as Decode>::decode(&mut r).unwrap();
204        assert_eq!(v0, 42);
205        assert!(r.rest().is_empty());
206    }
207
208    #[rstest]
209    #[case(&[0x92, 0x2a, 0x2b])] // fixarray
210    #[case(&[0xdc, 0x00, 0x02, 0x2a, 0x2b])] // array16(2)
211    fn tuple2_success(#[case] buf: &[u8]) {
212        let mut r = crate::io::SliceReader::new(buf);
213        let (a, b) = <(u8, u8) as Decode>::decode(&mut r).unwrap();
214        assert_eq!((a, b), (42, 43));
215        assert!(r.rest().is_empty());
216    }
217
218    #[rstest]
219    fn tuple3_success() {
220        let buf = &[0x93, 0x01, 0x02, 0x03];
221        let mut r = crate::io::SliceReader::new(buf);
222        let (a, b, c) = <(u8, u8, u8) as Decode>::decode(&mut r).unwrap();
223        assert_eq!((a, b, c), (1, 2, 3));
224        assert!(r.rest().is_empty());
225    }
226
227    #[rstest]
228    #[case(&[0x92, 0x01, 0x02])] // len 2
229    #[case(&[0xdc, 0x00, 0x04, 1, 2, 3, 4])] // len 4
230    fn tuple_len_mismatch(#[case] buf: &[u8]) {
231        let mut r = crate::io::SliceReader::new(buf);
232        let err = <(u8, u8, u8) as Decode>::decode(&mut r).unwrap_err();
233        assert!(matches!(err, Error::InvalidData));
234    }
235
236    #[rstest]
237    fn tuple_unexpected_format() {
238        let buf = &[0x81, 0x01, 0x02]; // map(1)
239        let mut r = crate::io::SliceReader::new(buf);
240        let err = <(u8,) as Decode>::decode(&mut r).unwrap_err();
241        assert!(matches!(err, Error::UnexpectedFormat));
242    }
243}