sark_core/http/
prefixed_int.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2pub enum PrefixedIntError {
3 NeedMore,
4 Overflow,
5}
6
7#[repr(transparent)]
19#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct PrefixedInt<const BITS: u8>(u64);
21
22#[doc(hidden)]
23pub trait ValidPrefixedIntWidth {
24 const MAX_PREFIX: u64;
25}
26
27macro_rules! valid_widths {
28 ($($bits:literal),+ $(,)?) => {
29 $(
30 impl ValidPrefixedIntWidth for PrefixedInt<$bits> {
31 const MAX_PREFIX: u64 = (1u64 << $bits) - 1;
32 }
33 )+
34 };
35}
36
37valid_widths!(1, 2, 3, 4, 5, 6, 7, 8);
38
39impl<const BITS: u8> PrefixedInt<BITS>
40where
41 Self: ValidPrefixedIntWidth,
42{
43 pub const fn new(value: u64) -> Self {
44 Self(value)
45 }
46
47 pub const fn get(self) -> u64 {
48 self.0
49 }
50
51 pub const fn encoded_len(self) -> usize {
52 if self.0 < Self::MAX_PREFIX {
53 return 1;
54 }
55 let remaining = self.0 - Self::MAX_PREFIX;
56 2 + ((remaining | 1).ilog2() / 7) as usize
57 }
58
59 pub fn encode(self, prefix_byte: u8, out: &mut impl Extend<u8>) {
60 let low_mask = Self::MAX_PREFIX as u8;
61 let high = prefix_byte & !low_mask;
62 if self.0 < Self::MAX_PREFIX {
63 out.extend([high | self.0 as u8]);
64 return;
65 }
66 out.extend([high | low_mask]);
67 let mut remaining = self.0 - Self::MAX_PREFIX;
68 while remaining >= 128 {
69 out.extend([((remaining & 0x7f) as u8) | 0x80]);
70 remaining >>= 7;
71 }
72 out.extend([remaining as u8]);
73 }
74
75 pub fn decode(buf: &[u8]) -> Result<(Self, usize), PrefixedIntError> {
76 let Some(&byte) = buf.first() else {
77 return Err(PrefixedIntError::NeedMore);
78 };
79 let first = (byte & Self::MAX_PREFIX as u8) as u64;
80 if first < Self::MAX_PREFIX {
81 return Ok((Self(first), 1));
82 }
83
84 let mut value = Self::MAX_PREFIX;
85 let mut shift = 0u32;
86 let mut pos = 1usize;
87 loop {
88 let Some(&byte) = buf.get(pos) else {
89 return Err(PrefixedIntError::NeedMore);
90 };
91 pos += 1;
92 let chunk = (byte & 0x7f) as u64;
93 let shifted = chunk.checked_shl(shift).ok_or(PrefixedIntError::Overflow)?;
94 value = value
95 .checked_add(shifted)
96 .ok_or(PrefixedIntError::Overflow)?;
97 if byte & 0x80 == 0 {
98 return Ok((Self(value), pos));
99 }
100 shift = shift.checked_add(7).ok_or(PrefixedIntError::Overflow)?;
101 if shift >= 64 {
102 return Err(PrefixedIntError::Overflow);
103 }
104 }
105 }
106}
107
108impl<const BITS: u8> From<PrefixedInt<BITS>> for u64
109where
110 PrefixedInt<BITS>: ValidPrefixedIntWidth,
111{
112 fn from(value: PrefixedInt<BITS>) -> Self {
113 value.get()
114 }
115}