Skip to main content

sark_http/field/metadata/packed/
prefix.rs

1use crate::field::{
2    Indexing,
3    metadata::{lower::plain, map::record},
4};
5
6/// Native packed-field prefix shared by retained field owners.
7#[derive(Clone, Copy, PartialEq, Eq)]
8pub struct Prefix {
9    name_len: u32,
10    value_len: u32,
11    indexing: Indexing,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum Error {
16    Prefix { required: usize, available: usize },
17    Length { name: usize, value: usize },
18    Payload { required: usize, available: usize },
19    Indexing { value: u8 },
20}
21
22impl Prefix {
23    pub const LEN: usize = 9;
24
25    pub(in crate::field::metadata) const fn new(
26        name_len: u32,
27        vlen: u32,
28        indexing: Indexing,
29    ) -> Self {
30        Self {
31            name_len,
32            value_len: vlen,
33            indexing,
34        }
35    }
36
37    pub(in crate::field::metadata) fn try_new(
38        name: usize,
39        value: usize,
40        indexing: Indexing,
41    ) -> Result<Self, plain::Error> {
42        use plain::Error;
43        let name_len = u32::try_from(name).map_err(|_| Error::Name(name))?;
44        let vlen = u32::try_from(value).map_err(|_| Error::Value(value))?;
45        Ok(Self::new(name_len, vlen, indexing))
46    }
47
48    pub(in crate::field::metadata) fn to_bytes(self) -> [u8; Self::LEN] {
49        let [n0, n1, n2, n3] = self.name_len.to_ne_bytes();
50        let [v0, v1, v2, v3] = self.value_len.to_ne_bytes();
51        [n0, n1, n2, n3, v0, v1, v2, v3, self.indexing as u8]
52    }
53
54    pub fn try_read(bytes: &[u8]) -> Result<Self, Error> {
55        let Some(prefix) = bytes.first_chunk() else {
56            return Err(Error::Prefix {
57                required: Self::LEN,
58                available: bytes.len(),
59            });
60        };
61        let indexing =
62            Indexing::from_byte(prefix[8]).ok_or(Error::Indexing { value: prefix[8] })?;
63        Ok(Self::decode(prefix, indexing))
64    }
65
66    pub(super) fn decode(prefix: &[u8; Self::LEN], indexing: Indexing) -> Self {
67        // SAFETY: the admitted nine-byte prefix contains both native-endian u32
68        // lengths. Reading them unaligned preserves every possible bit pattern.
69        let [name_len, vlen] = unsafe { prefix.as_ptr().cast::<[u32; 2]>().read_unaligned() };
70        Self {
71            name_len,
72            value_len: vlen,
73            indexing,
74        }
75    }
76
77    pub const fn name_len(self) -> u32 {
78        self.name_len
79    }
80
81    pub const fn value_len(self) -> u32 {
82        self.value_len
83    }
84
85    pub const fn indexing(self) -> Indexing {
86        self.indexing
87    }
88
89    pub fn try_take<'a>(
90        self,
91        bytes: &'a [u8],
92        name_len: usize,
93    ) -> Result<(record::Entry<'a>, &'a [u8]), Error> {
94        let fields = bytes.get(Self::LEN..).ok_or(Error::Prefix {
95            required: Self::LEN,
96            available: bytes.len(),
97        })?;
98        let value = self.value_len as usize;
99        let used = name_len.checked_add(value).ok_or(Error::Length {
100            name: name_len,
101            value,
102        })?;
103        if used > fields.len() {
104            return Err(Error::Payload {
105                required: used,
106                available: fields.len(),
107            });
108        }
109        let (packed, rest) = fields.split_at(used);
110        let (name, value) = packed.split_at(name_len);
111        Ok((
112            record::Entry::new(name, value).with_index(self.indexing),
113            rest,
114        ))
115    }
116}