sark_http/field/metadata/packed/
prefix.rs1use crate::field::{
2 Indexing,
3 metadata::{lower::plain, map::record},
4};
5
6#[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 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}