lilliput_core/encoder/
map.rs

1use crate::{
2    error::Result,
3    header::{CompactMapHeader, ExtendedMapHeader, MapHeader},
4    io::Write,
5    num::WithPackedBeBytes as _,
6    value::{Map, MapValue},
7};
8
9use super::Encoder;
10
11impl<W> Encoder<W>
12where
13    W: Write,
14{
15    // MARK: - Value
16
17    /// Encodes a map value.
18    pub fn encode_map(&mut self, value: &Map) -> Result<()> {
19        self.encode_map_header(&self.header_for_map_len(value.len()))?;
20
21        for (key, value) in value {
22            self.encode_value(key)?;
23            self.encode_value(value)?;
24        }
25
26        Ok(())
27    }
28
29    /// Encodes a map value, from a `MapValue`.
30    pub fn encode_map_value(&mut self, value: &MapValue) -> Result<()> {
31        self.encode_map(&value.0)
32    }
33
34    // MARK: - Header
35
36    /// Encodes a map value's header.
37    pub fn encode_map_header(&mut self, header: &MapHeader) -> Result<()> {
38        let mut byte = MapHeader::TYPE_BITS;
39
40        match *header {
41            MapHeader::Compact(CompactMapHeader { len }) => {
42                byte |= MapHeader::COMPACT_VARIANT_BIT;
43                byte |= len & MapHeader::COMPACT_LEN_BITS;
44
45                // Push the value's header:
46                self.push_byte(byte)
47            }
48            MapHeader::Extended(ExtendedMapHeader { len }) => {
49                len.with_packed_be_bytes(self.config.lengths.packing, |bytes| {
50                    let width = bytes.len() as u8;
51
52                    byte |= (width - 1) & MapHeader::EXTENDED_LEN_WIDTH_BITS;
53
54                    #[cfg(feature = "tracing")]
55                    tracing::debug!(
56                        byte = crate::binary::fmt_byte(byte),
57                        bytes = format!("{:b}", crate::binary::BytesSlice(bytes)),
58                        len = len
59                    );
60
61                    // Push the value's header:
62                    self.push_byte(byte)?;
63
64                    // Push the value's length:
65                    self.push_bytes(bytes)
66                })
67            }
68        }
69    }
70
71    /// Creates a header for a map value, from its length.
72    pub fn header_for_map_len(&self, len: usize) -> MapHeader {
73        MapHeader::for_len(len, self.config.lengths.packing)
74    }
75}