lilliput_core/decoder/
map.rs

1use crate::{
2    error::Result,
3    header::MapHeader,
4    marker::Marker,
5    value::{Map, MapValue},
6};
7
8use super::{Decoder, Read};
9
10impl<'de, R> Decoder<R>
11where
12    R: Read<'de>,
13{
14    // MARK: - Value
15
16    /// Decodes a map value.
17    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
18    pub fn decode_map(&mut self) -> Result<Map> {
19        let header = self.decode_map_header()?;
20        self.decode_map_of(header)
21    }
22
23    /// Decodes a map value, as a `MapValue`.
24    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
25    pub fn decode_map_value(&mut self) -> Result<MapValue> {
26        self.decode_map().map(From::from)
27    }
28
29    // MARK: - Header
30
31    /// Decodes a map value's header.
32    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
33    pub fn decode_map_header(&mut self) -> Result<MapHeader> {
34        let byte = self.pull_byte_expecting(Marker::Map)?;
35
36        let is_compact = (byte & MapHeader::COMPACT_VARIANT_BIT) != 0b0;
37
38        if is_compact {
39            let len = byte & MapHeader::COMPACT_LEN_BITS;
40
41            #[cfg(feature = "tracing")]
42            tracing::debug!(
43                byte = crate::binary::fmt_byte(byte),
44                is_compact = true,
45                len = len
46            );
47
48            Ok(MapHeader::compact(len))
49        } else {
50            let len_width = 1 + (byte & MapHeader::EXTENDED_LEN_WIDTH_BITS);
51            let len = self.pull_len_bytes(len_width)?;
52
53            #[cfg(feature = "tracing")]
54            tracing::debug!(
55                byte = crate::binary::fmt_byte(byte),
56                is_compact = false,
57                len = len
58            );
59
60            Ok(MapHeader::extended(len))
61        }
62    }
63
64    // MARK: - Skip
65
66    /// Skips the map value for a given `header`.
67    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
68    pub fn skip_map_value_of(&mut self, header: MapHeader) -> Result<()> {
69        let len: usize = match header {
70            MapHeader::Compact(header) => header.len().into(),
71            MapHeader::Extended(header) => header.len(),
72        };
73
74        for _ in 0..len {
75            self.skip_value()?; // key
76            self.skip_value()?; // value
77        }
78
79        Ok(())
80    }
81
82    // MARK: - Body
83
84    /// Decodes map value for a given `header`, as a `MapValue`.
85    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
86    pub fn decode_map_value_of(&mut self, header: MapHeader) -> Result<MapValue> {
87        self.decode_map_of(header).map(From::from)
88    }
89
90    // MARK: - Private
91
92    /// Decodes map value for a given `header`.
93    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
94    fn decode_map_of(&mut self, header: MapHeader) -> Result<Map> {
95        let mut map = Map::default();
96
97        for _ in 0..header.len() {
98            let key = self.decode_value()?;
99            let value = self.decode_value()?;
100            map.insert(key, value);
101        }
102
103        Ok(map)
104    }
105}