Skip to main content

sark_http/request/
span.rs

1use core::{num::NonZero, ops};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Error {
5    Order {
6        start: usize,
7        end: usize,
8    },
9    Overflow {
10        start: usize,
11        len: usize,
12    },
13    Bounds {
14        start: usize,
15        len: usize,
16    },
17    Shift {
18        start: usize,
19        len: usize,
20        base: usize,
21    },
22}
23
24/// Compact byte range into one retained wire owner.
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub struct Span {
27    start_plus_one: NonZero<u32>,
28    len: u32,
29}
30
31impl Span {
32    pub(crate) const fn from_target(target: super::Target) -> Self {
33        Self::pack(target.start(), target.len())
34    }
35
36    pub fn checked(start: usize, len: usize) -> Result<Self, Error> {
37        let Some(end) = start.checked_add(len) else {
38            return Err(Error::Overflow { start, len });
39        };
40        if start >= u32::MAX as usize || end > u32::MAX as usize {
41            return Err(Error::Bounds { start, len });
42        }
43        Ok(Self::pack(start, len))
44    }
45
46    /// Retains a range that begins at the start of its block.
47    ///
48    /// The request line measures its method before every target it admits, so
49    /// the method range is the block prefix and its start needs no proof.
50    pub(crate) const fn from_start(len: u32) -> Self {
51        Self::pack(0, len as usize)
52    }
53
54    pub fn from_range(range: ops::Range<usize>) -> Result<Self, Error> {
55        let Some(len) = range.end.checked_sub(range.start) else {
56            return Err(Error::Order {
57                start: range.start,
58                end: range.end,
59            });
60        };
61        if range.start >= u32::MAX as usize || range.end > u32::MAX as usize {
62            return Err(Error::Bounds {
63                start: range.start,
64                len,
65            });
66        }
67        Ok(Self::pack(range.start, len))
68    }
69
70    pub const fn start(self) -> usize {
71        (self.start_plus_one.get() - 1) as usize
72    }
73
74    pub const fn len(self) -> usize {
75        self.len as usize
76    }
77
78    pub const fn is_empty(self) -> bool {
79        self.len == 0
80    }
81
82    pub const fn end(self) -> usize {
83        self.start() + self.len()
84    }
85
86    /// The range moved to a successor start its owner's growth check admitted.
87    ///
88    /// `start` is the value that check produced, so the move consumes
89    /// the bounded start instead of re-deriving the bound that admitted it.
90    pub(crate) const fn shifted_to(self, start: NonZero<u32>) -> Self {
91        Self {
92            start_plus_one: start,
93            len: self.len,
94        }
95    }
96
97    pub fn get(self, input: &[u8]) -> Option<&[u8]> {
98        input.get(self.start()..self.end())
99    }
100
101    pub fn shifted(self, base: usize) -> Result<Self, Error> {
102        let start = self.start();
103        let len = self.len();
104        let Some(shifted) = base.checked_add(start) else {
105            return Err(Error::Shift { start, len, base });
106        };
107        let Some(end) = shifted.checked_add(len) else {
108            return Err(Error::Shift { start, len, base });
109        };
110        if shifted >= u32::MAX as usize || end > u32::MAX as usize {
111            return Err(Error::Shift { start, len, base });
112        }
113        Ok(Self::pack(shifted, len))
114    }
115
116    /// Stores the bounds admitted by the caller without another failure path.
117    const fn pack(start: usize, len: usize) -> Self {
118        Self {
119            start_plus_one: NonZero::<u32>::MIN.saturating_add(start as u32),
120            len: len as u32,
121        }
122    }
123}
124
125impl Default for Span {
126    fn default() -> Self {
127        Self::from_start(0)
128    }
129}
130
131/// A wire range retained together with the block it was measured in; the parse
132/// that measures a range reaches [`Self::try_new`] once and retains both the
133/// range and its bytes, so later layers never re-derive either from the owner.
134#[derive(Clone, Copy)]
135pub(crate) struct Retained<'owner> {
136    bytes: &'owner [u8],
137    span: Span,
138}
139
140impl<'owner> Retained<'owner> {
141    pub(crate) fn try_new(owner: &'owner [u8], range: ops::Range<u32>) -> Result<Self, Error> {
142        let span = Span::from_range(range.start as usize..range.end as usize)?;
143        let start = span.start();
144        let bytes = owner.get(start..span.end()).ok_or(Error::Bounds {
145            start,
146            len: span.len(),
147        })?;
148        Ok(Self { bytes, span })
149    }
150
151    pub(crate) const fn bytes(self) -> &'owner [u8] {
152        self.bytes
153    }
154
155    pub(crate) const fn span(self) -> Span {
156        self.span
157    }
158}
159
160const _: () = {
161    assert!(core::mem::size_of::<Span>() == 8);
162    assert!(core::mem::size_of::<Option<Span>>() == 8);
163};