Skip to main content

sark_core/request/
field.rs

1//! Parsed request field contracts.
2
3use std::{mem, ops};
4
5use o3::{
6    alloc,
7    buffer::{storage, write::consume},
8};
9use sark_http::{
10    field::text::{Ascii, IntError},
11    h1::field::Entry,
12    request::span,
13};
14
15use crate::request::path;
16
17/// Receives one generated field-name prefix match.
18pub trait Prefix<S: Copy>: Sized {
19    type Output;
20
21    fn rest(&self) -> &[u8];
22
23    fn user(self, slot: S, colon: usize) -> Self::Output;
24
25    fn miss(self, start: usize) -> Self::Output;
26
27    fn short(self) -> Self::Output;
28}
29
30#[repr(u8)]
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub enum Error {
33    Capacity(consume::Error),
34    Exhausted(alloc::Exhausted),
35    Path(path::Error),
36    Span(span::Error),
37    Integer {
38        start: usize,
39        end: usize,
40        cause: IntError,
41    },
42    Boolean {
43        start: usize,
44        end: usize,
45    },
46    Order {
47        start: usize,
48        end: usize,
49        capacity: usize,
50    },
51    Bounds {
52        start: usize,
53        end: usize,
54        capacity: usize,
55    },
56    AcceptEncoding(sark_http::field::head::Error),
57}
58
59impl From<storage::AllocError> for Error {
60    fn from(error: storage::AllocError) -> Self {
61        match error {
62            storage::AllocError::Capacity(error) => Self::Capacity(error),
63            storage::AllocError::Exhausted(error) => Self::Exhausted(error),
64        }
65    }
66}
67
68pub trait HeaderValue: AsRef<[u8]> {
69    fn try_span(&self) -> Result<span::Span, Error>;
70}
71
72impl HeaderValue for storage::Shared {
73    fn try_span(&self) -> Result<span::Span, Error> {
74        span::Span::checked(0, self.len()).map_err(Error::Span)
75    }
76}
77
78pub struct SliceValue<'a> {
79    value: &'a [u8],
80    span: span::Span,
81}
82
83impl<'a> From<Entry<'a>> for SliceValue<'a> {
84    fn from(entry: Entry<'a>) -> Self {
85        Self {
86            value: entry.value(),
87            span: entry.value_span(),
88        }
89    }
90}
91
92impl<'a> SliceValue<'a> {
93    pub fn try_slice(value: &'a [u8], start: usize) -> Result<Self, Error> {
94        let span = span::Span::checked(start, value.len()).map_err(Error::Span)?;
95        Ok(Self { value, span })
96    }
97
98    pub fn try_new(raw: &'a [u8], range: ops::Range<usize>) -> Result<Self, Error> {
99        let start = range.start;
100        let end = range.end;
101        let capacity = raw.len();
102        if start > end {
103            return Err(Error::Order {
104                start,
105                end,
106                capacity,
107            });
108        }
109        let value = raw.get(start..end).ok_or(Error::Bounds {
110            start,
111            end,
112            capacity,
113        })?;
114        let span = span::Span::from_range(start..end).map_err(Error::Span)?;
115        Ok(Self { value, span })
116    }
117
118    pub fn try_at(raw: &'a [u8], span: span::Span) -> Result<Self, Error> {
119        let start = span.start();
120        let end = span.end();
121        let value = raw.get(start..end).ok_or(Error::Bounds {
122            start,
123            end,
124            capacity: raw.len(),
125        })?;
126        Ok(Self { value, span })
127    }
128}
129
130impl HeaderValue for SliceValue<'_> {
131    fn try_span(&self) -> Result<span::Span, Error> {
132        Ok(self.span)
133    }
134}
135
136impl AsRef<[u8]> for SliceValue<'_> {
137    fn as_ref(&self) -> &[u8] {
138        self.value
139    }
140}
141
142pub trait Value: Sized {
143    fn parse_value<V: HeaderValue>(value: &V) -> Result<Self, Error>;
144}
145
146pub trait Path: Sized {
147    fn try_parse(path: &path::Target<'_>, range: ops::Range<usize>) -> Result<Self, Error> {
148        Self::parse(path.try_capture(range).map_err(Error::Path)?)
149    }
150
151    fn parse(capture: path::Capture<'_>) -> Result<Self, Error>;
152}
153
154impl Value for storage::Shared {
155    fn parse_value<V: HeaderValue>(value: &V) -> Result<Self, Error> {
156        storage::Shared::try_copy(value.as_ref()).map_err(Error::from)
157    }
158}
159
160impl Value for usize {
161    fn parse_value<V: HeaderValue>(value: &V) -> Result<Self, Error> {
162        let span = value.try_span()?;
163        integer(
164            Ascii::new(value.as_ref()).parse_usize(),
165            span.start()..span.end(),
166        )
167    }
168}
169
170impl Path for usize {
171    fn parse(capture: path::Capture<'_>) -> Result<Self, Error> {
172        integer(
173            Ascii::new(capture.as_bytes()).parse_usize(),
174            capture.range(),
175        )
176    }
177}
178
179impl Value for u64 {
180    fn parse_value<V: HeaderValue>(value: &V) -> Result<Self, Error> {
181        let span = value.try_span()?;
182        integer(
183            Ascii::new(value.as_ref()).parse_u64(),
184            span.start()..span.end(),
185        )
186    }
187}
188
189impl Path for u64 {
190    fn parse(capture: path::Capture<'_>) -> Result<Self, Error> {
191        integer(Ascii::new(capture.as_bytes()).parse_u64(), capture.range())
192    }
193}
194
195impl Value for bool {
196    fn parse_value<V: HeaderValue>(value: &V) -> Result<Self, Error> {
197        let span = value.try_span()?;
198        boolean(value.as_ref(), span.start()..span.end())
199    }
200}
201
202impl Path for bool {
203    fn parse(capture: path::Capture<'_>) -> Result<Self, Error> {
204        boolean(capture.as_bytes(), capture.range())
205    }
206}
207
208fn integer<T>(value: Result<T, IntError>, range: ops::Range<usize>) -> Result<T, Error> {
209    value.map_err(|cause| Error::Integer {
210        start: range.start,
211        end: range.end,
212        cause,
213    })
214}
215
216fn boolean(value: &[u8], range: ops::Range<usize>) -> Result<bool, Error> {
217    if value.eq_ignore_ascii_case(b"true") || value == b"1" {
218        return Ok(true);
219    }
220    if value.eq_ignore_ascii_case(b"false") || value == b"0" {
221        return Ok(false);
222    }
223    Err(Error::Boolean {
224        start: range.start,
225        end: range.end,
226    })
227}
228
229const _: () = {
230    assert!(mem::size_of::<SliceValue<'_>>() == mem::size_of::<usize>() * 3);
231    assert!(mem::size_of::<Option<SliceValue<'_>>>() == mem::size_of::<SliceValue<'_>>());
232    assert!(mem::size_of::<Error>() == mem::size_of::<usize>() * 5);
233    assert!(mem::size_of::<Option<Error>>() == mem::size_of::<Error>());
234    assert!(mem::size_of::<Result<(), Error>>() == mem::size_of::<Error>());
235    assert!(!mem::needs_drop::<SliceValue<'_>>());
236    assert!(!mem::needs_drop::<Error>());
237};