Skip to main content

sark_http/h1/field/
scan.rs

1use core::num::NonZero;
2
3use o3::buffer::{self, write};
4use write::CopyError;
5
6use crate::h1::field::{self, Cursor, Entry, Limit, syntax};
7
8/// Append-only ownership and syntax progress through a selected field suffix.
9/// Bytes before the starting offset are retained unchanged, but are not validated.
10pub struct State<S> {
11    source: S,
12    cursor: Cursor,
13}
14
15pub enum Progress<S> {
16    More(State<S>),
17    Complete(Complete<S>),
18}
19
20/// The original owner and the suffix terminator established by its field cursor.
21/// This does not certify any bytes preceding the cursor's starting offset.
22pub struct Complete<S> {
23    source: S,
24    end: field::End,
25}
26
27#[derive(Debug)]
28pub enum Error<E> {
29    Syntax(syntax::Error),
30    Sink(E),
31}
32
33impl<S: buffer::raw::Source> State<S> {
34    pub const fn source(&self) -> &S {
35        &self.source
36    }
37
38    /// Starts syntax admission at `start`, charging new fields after `seen`.
39    /// The skipped prefix and its count remain the caller's proof obligations.
40    pub fn try_new(
41        source: S,
42        start: usize,
43        seen: usize,
44        fields: usize,
45        line: usize,
46    ) -> Result<Self, (S, syntax::Error)> {
47        if start > source.as_ref().len() {
48            return Err((source, syntax::Error::Invalid));
49        }
50        match Cursor::seed(start, seen, Limit::new(fields, line)) {
51            Ok(cursor) => Ok(Self { source, cursor }),
52            Err(error) => Err((source, error)),
53        }
54    }
55
56    pub fn advance<E>(
57        mut self,
58        mut sink: impl FnMut(Entry<'_>) -> Result<(), E>,
59    ) -> Result<Progress<S>, (S, Error<E>)> {
60        loop {
61            match self.cursor.advance(self.source.as_ref()) {
62                Ok(field::Progress::Field(field)) => {
63                    if let Err(error) = sink(field) {
64                        return Err((self.source, Error::Sink(error)));
65                    }
66                }
67                Ok(field::Progress::More) => return Ok(Progress::More(self)),
68                Ok(field::Progress::End(end)) => {
69                    return Ok(Progress::Complete(Complete {
70                        source: self.source,
71                        end,
72                    }));
73                }
74                Err(error) => return Err((self.source, Error::Syntax(error))),
75            }
76        }
77    }
78
79    /// Copies the exact source while retaining its already established progress.
80    pub fn try_copy<D>(&self, target: D) -> Result<State<D>, (D, CopyError<D::Error>)>
81    where
82        D: buffer::raw::Source + write::Sink,
83    {
84        let target = write::try_copy(target, self.source.as_ref())?;
85        Ok(State {
86            source: target,
87            cursor: self.cursor,
88        })
89    }
90}
91
92impl<S: write::Sink> State<S> {
93    pub fn try_extend(&mut self, bytes: &[u8]) -> Result<(), S::Error> {
94        self.source.write_slice(bytes)
95    }
96}
97
98impl<S: buffer::raw::Source> AsRef<[u8]> for State<S> {
99    fn as_ref(&self) -> &[u8] {
100        self.source.as_ref()
101    }
102}
103
104impl<S> Complete<S> {
105    /// Returns the owner, empty-line start, and end of the scanned suffix.
106    /// The prefix before the original starting offset is not certified here.
107    pub fn into_parts(self) -> (S, usize, NonZero<u32>) {
108        (self.source, self.end.fields() as usize, self.end.wire_len())
109    }
110}