Skip to main content

craft_codec/
index.rs

1use crate::{Error, Result};
2
3/// Compact positive lengths, stored as `length - 1`.
4///
5/// The width is selected from the configured maximum, not the object length.
6/// Public variants allow external persistence without enabling `serde`.
7#[derive(Clone, Debug, Eq, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum Lengths {
10    /// Lengths up to and including 65,536 bytes.
11    U16(Vec<u16>),
12    /// Lengths up to and including 4,294,967,296 bytes.
13    U32(Vec<u32>),
14    /// Larger lengths. An encoded `u64::MAX` is invalid.
15    U64(Vec<u64>),
16}
17
18impl Lengths {
19    fn empty(max_length: u64) -> Self {
20        match max_length {
21            ..=65_536 => Self::U16(Vec::new()),
22            65_537..=4_294_967_296 => Self::U32(Vec::new()),
23            _ => Self::U64(Vec::new()),
24        }
25    }
26
27    /// Create an empty table with the width required by `max_length`.
28    pub fn new(max_length: u64) -> Result<Self> {
29        if max_length == 0 {
30            return Err(Error::InvalidFrameSize);
31        }
32        Ok(Self::empty(max_length))
33    }
34
35    pub(crate) fn for_config(config: &crate::Config) -> Self {
36        Self::empty(config.max_frame_len())
37    }
38
39    /// Number of entries.
40    pub fn len(&self) -> usize {
41        match self {
42            Self::U16(v) => v.len(),
43            Self::U32(v) => v.len(),
44            Self::U64(v) => v.len(),
45        }
46    }
47    /// Whether there are no entries.
48    pub fn is_empty(&self) -> bool {
49        self.len() == 0
50    }
51    /// Bytes per entry, excluding the vector's spare capacity.
52    pub fn width(&self) -> usize {
53        match self {
54            Self::U16(_) => 2,
55            Self::U32(_) => 4,
56            Self::U64(_) => 8,
57        }
58    }
59    /// Decode an entry. Returns `None` for an absent or overflowing entry.
60    pub fn get(&self, index: usize) -> Option<u64> {
61        match self {
62            Self::U16(v) => v.get(index).map(|v| u64::from(*v) + 1),
63            Self::U32(v) => v.get(index).map(|v| u64::from(*v) + 1),
64            Self::U64(v) => v.get(index).and_then(|v| v.checked_add(1)),
65        }
66    }
67    /// Append a positive length that fits this table's width.
68    pub fn push(&mut self, length: u64) -> Result<()> {
69        let encoded = length.checked_sub(1).ok_or(Error::InvalidFrameSize)?;
70        match self {
71            Self::U16(v) => {
72                let value = u16::try_from(encoded).map_err(|_| Error::Overflow)?;
73                v.try_reserve(1).map_err(|_| Error::Allocation)?;
74                v.push(value);
75            }
76            Self::U32(v) => {
77                let value = u32::try_from(encoded).map_err(|_| Error::Overflow)?;
78                v.try_reserve(1).map_err(|_| Error::Allocation)?;
79                v.push(value);
80            }
81            Self::U64(v) => {
82                v.try_reserve(1).map_err(|_| Error::Allocation)?;
83                v.push(encoded);
84            }
85        }
86        Ok(())
87    }
88    pub(crate) fn reserve_one(&mut self) -> Result<()> {
89        match self {
90            Self::U16(v) => v.try_reserve(1),
91            Self::U32(v) => v.try_reserve(1),
92            Self::U64(v) => v.try_reserve(1),
93        }
94        .map_err(|_| Error::Allocation)
95    }
96}