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    /// Create an empty table with the width required by `max_length`.
20    pub fn new(max_length: u64) -> Result<Self> {
21        match max_length {
22            0 => Err(Error::InvalidFrameSize),
23            1..=65_536 => Ok(Self::U16(Vec::new())),
24            65_537..=4_294_967_296 => Ok(Self::U32(Vec::new())),
25            _ => Ok(Self::U64(Vec::new())),
26        }
27    }
28
29    /// Number of entries.
30    pub fn len(&self) -> usize {
31        match self {
32            Self::U16(v) => v.len(),
33            Self::U32(v) => v.len(),
34            Self::U64(v) => v.len(),
35        }
36    }
37    /// Whether there are no entries.
38    pub fn is_empty(&self) -> bool {
39        self.len() == 0
40    }
41    /// Bytes per entry, excluding the vector's spare capacity.
42    pub fn width(&self) -> usize {
43        match self {
44            Self::U16(_) => 2,
45            Self::U32(_) => 4,
46            Self::U64(_) => 8,
47        }
48    }
49    /// Decode an entry. Returns `None` for an absent or overflowing entry.
50    pub fn get(&self, index: usize) -> Option<u64> {
51        match self {
52            Self::U16(v) => v.get(index).map(|v| u64::from(*v) + 1),
53            Self::U32(v) => v.get(index).map(|v| u64::from(*v) + 1),
54            Self::U64(v) => v.get(index).and_then(|v| v.checked_add(1)),
55        }
56    }
57    /// Append a positive length that fits this table's width.
58    pub fn push(&mut self, length: u64) -> Result<()> {
59        let encoded = length.checked_sub(1).ok_or(Error::InvalidFrameSize)?;
60        match self {
61            Self::U16(v) => {
62                let value = u16::try_from(encoded).map_err(|_| Error::Overflow)?;
63                v.try_reserve(1).map_err(|_| Error::Allocation)?;
64                v.push(value);
65            }
66            Self::U32(v) => {
67                let value = u32::try_from(encoded).map_err(|_| Error::Overflow)?;
68                v.try_reserve(1).map_err(|_| Error::Allocation)?;
69                v.push(value);
70            }
71            Self::U64(v) => {
72                v.try_reserve(1).map_err(|_| Error::Allocation)?;
73                v.push(encoded);
74            }
75        }
76        Ok(())
77    }
78    pub(crate) fn reserve_one(&mut self) -> Result<()> {
79        match self {
80            Self::U16(v) => v.try_reserve(1),
81            Self::U32(v) => v.try_reserve(1),
82            Self::U64(v) => v.try_reserve(1),
83        }
84        .map_err(|_| Error::Allocation)
85    }
86}