use core::num::NonZero;
use o3::buffer::{self, write};
use write::CopyError;
use crate::h1::field::{self, Cursor, Entry, Limit, syntax};
pub struct State<S> {
source: S,
cursor: Cursor,
}
pub enum Progress<S> {
More(State<S>),
Complete(Complete<S>),
}
pub struct Complete<S> {
source: S,
end: field::End,
}
#[derive(Debug)]
pub enum Error<E> {
Syntax(syntax::Error),
Sink(E),
}
impl<S: buffer::raw::Source> State<S> {
pub const fn source(&self) -> &S {
&self.source
}
pub fn try_new(
source: S,
start: usize,
seen: usize,
fields: usize,
line: usize,
) -> Result<Self, (S, syntax::Error)> {
if start > source.as_ref().len() {
return Err((source, syntax::Error::Invalid));
}
match Cursor::seed(start, seen, Limit::new(fields, line)) {
Ok(cursor) => Ok(Self { source, cursor }),
Err(error) => Err((source, error)),
}
}
pub fn advance<E>(
mut self,
mut sink: impl FnMut(Entry<'_>) -> Result<(), E>,
) -> Result<Progress<S>, (S, Error<E>)> {
loop {
match self.cursor.advance(self.source.as_ref()) {
Ok(field::Progress::Field(field)) => {
if let Err(error) = sink(field) {
return Err((self.source, Error::Sink(error)));
}
}
Ok(field::Progress::More) => return Ok(Progress::More(self)),
Ok(field::Progress::End(end)) => {
return Ok(Progress::Complete(Complete {
source: self.source,
end,
}));
}
Err(error) => return Err((self.source, Error::Syntax(error))),
}
}
}
pub fn try_copy<D>(&self, target: D) -> Result<State<D>, (D, CopyError<D::Error>)>
where
D: buffer::raw::Source + write::Sink,
{
let target = write::try_copy(target, self.source.as_ref())?;
Ok(State {
source: target,
cursor: self.cursor,
})
}
}
impl<S: write::Sink> State<S> {
pub fn try_extend(&mut self, bytes: &[u8]) -> Result<(), S::Error> {
self.source.write_slice(bytes)
}
}
impl<S: buffer::raw::Source> AsRef<[u8]> for State<S> {
fn as_ref(&self) -> &[u8] {
self.source.as_ref()
}
}
impl<S> Complete<S> {
pub fn into_parts(self) -> (S, usize, NonZero<u32>) {
(self.source, self.end.fields() as usize, self.end.wire_len())
}
}