messagepack_core/decode/
map.rs

1//! Map decoding helpers.
2
3use core::marker::PhantomData;
4
5use super::{Decode, Error, NbyteReader, Result};
6use crate::formats::Format;
7
8/// Decode a MessagePack map of `K -> V` into `Map` collecting iterator.
9pub struct MapDecoder<Map, K, V>(PhantomData<(Map, K, V)>);
10
11fn decode_kv<'a, K, V>(buf: &'a [u8]) -> Result<(K::Value, V::Value, &'a [u8])>
12where
13    K: Decode<'a>,
14    V: Decode<'a>,
15{
16    let (k, buf) = K::decode(buf)?;
17    let (v, buf) = V::decode(buf)?;
18    Ok((k, v, buf))
19}
20
21impl<'a, Map, K, V> Decode<'a> for MapDecoder<Map, K, V>
22where
23    K: Decode<'a>,
24    V: Decode<'a>,
25    Map: FromIterator<(K::Value, V::Value)>,
26{
27    type Value = Map;
28
29    fn decode(buf: &'a [u8]) -> Result<(Self::Value, &'a [u8])> {
30        let (format, buf) = Format::decode(buf)?;
31        match format {
32            Format::FixMap(_) | Format::Map16 | Format::Map32 => {
33                Self::decode_with_format(format, buf)
34            }
35            _ => Err(Error::UnexpectedFormat),
36        }
37    }
38
39    fn decode_with_format(format: Format, buf: &'a [u8]) -> Result<(Self::Value, &'a [u8])> {
40        let (len, buf) = match format {
41            Format::FixMap(len) => (len.into(), buf),
42            Format::Map16 => NbyteReader::<2>::read(buf)?,
43            Format::Map32 => NbyteReader::<4>::read(buf)?,
44            _ => return Err(Error::UnexpectedFormat),
45        };
46
47        let mut has_err = None;
48        let mut buf_ptr = buf;
49        let collector =
50            core::iter::repeat_n((), len).map_while(|_| match decode_kv::<K, V>(buf_ptr) {
51                Ok((k, v, b)) => {
52                    buf_ptr = b;
53                    Some((k, v))
54                }
55                Err(e) => {
56                    has_err = Some(e);
57                    None
58                }
59            });
60        let res = Map::from_iter(collector);
61
62        if let Some(e) = has_err {
63            Err(e)
64        } else {
65            Ok((res, buf_ptr))
66        }
67    }
68}