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