Skip to main content

sark_http/h1/field/
expect.rs

1use crate::{field, h1::framing};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Error {
5    Unsupported,
6}
7
8/// Borrow-free action admitted from an HTTP/1 `Expect` field.
9#[repr(u8)]
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub enum Decision {
12    #[default]
13    None,
14    Continue,
15}
16
17impl Decision {
18    pub const fn is_continue(self) -> bool {
19        matches!(self, Self::Continue)
20    }
21}
22
23/// One-byte, borrow-free request expectation state.
24#[repr(transparent)]
25#[derive(Clone, Copy, Default, PartialEq, Eq)]
26pub struct State(u8);
27
28impl State {
29    const CONTINUE: u8 = 1 << 0;
30    const UNSUPPORTED: u8 = 1 << 1;
31
32    pub fn push(mut self, value: &[u8]) -> Self {
33        for raw in value.split(|byte| *byte == b',') {
34            let token = field::Error::trim_ows(raw);
35            if token.is_empty() {
36                continue;
37            }
38            if token.eq_ignore_ascii_case(b"100-continue") {
39                self.0 |= Self::CONTINUE;
40            } else {
41                self.0 |= Self::UNSUPPORTED;
42            }
43        }
44        self
45    }
46
47    pub const fn finish(self, body: framing::RequestBody) -> Result<Decision, Error> {
48        if self.0 & Self::UNSUPPORTED != 0 {
49            return Err(Error::Unsupported);
50        }
51        Ok(
52            if self.0 & Self::CONTINUE != 0 && !matches!(body, framing::RequestBody::Empty) {
53                Decision::Continue
54            } else {
55                Decision::None
56            },
57        )
58    }
59}
60
61const _: () = assert!(core::mem::size_of::<Decision>() == 1);
62const _: () = assert!(core::mem::size_of::<State>() == 1);