use crate::__private::IncomingName;
use crate::field_ref::IntoField;
use crate::{FieldError, FieldNames, FieldRef};
pub trait FieldSection<'a>: Sized {
const NAMES: FieldNames;
#[doc(hidden)]
const REJECTS_UNKNOWN: bool = Self::NAMES.rejects_unknown();
#[doc(hidden)]
type Identity: 'static;
#[doc(hidden)]
type Builder;
#[doc(hidden)]
fn builder() -> Self::Builder;
#[doc(hidden)]
fn accept(
builder: &mut Self::Builder,
name: &str,
value: &'a [u8],
position: usize,
) -> Result<bool, FieldError>;
#[doc(hidden)]
fn accept_declaration(
builder: &mut Self::Builder,
declaration: usize,
value: &'a [u8],
position: usize,
) -> Result<(), FieldError>;
#[doc(hidden)]
fn finish(builder: Self::Builder) -> Result<Self, FieldError>;
fn interpret<I>(fields: I) -> Result<Self, FieldError>
where
I: IntoIterator,
I::Item: IntoField<'a, Self>,
{
interpret::<Self, I, Vec<FieldRef<'a>>>(fields, None)
}
fn partition<I, R>(fields: I) -> Result<(Self, R), FieldError>
where
I: IntoIterator,
I::Item: IntoField<'a, Self>,
R: Default + Extend<FieldRef<'a>>,
{
let mut remainder = R::default();
let section = interpret::<Self, I, R>(fields, Some(&mut remainder))?;
Ok((section, remainder))
}
}
fn interpret<'a, S, I, R>(fields: I, mut remainder: Option<&mut R>) -> Result<S, FieldError>
where
S: FieldSection<'a>,
I: IntoIterator,
I::Item: IntoField<'a, S>,
R: Extend<FieldRef<'a>>,
{
let mut builder = S::builder();
for (index, field) in fields.into_iter().enumerate() {
let field = field.into_field(index);
let unclaimed = match field.name {
IncomingName::Declaration(declaration) => {
S::accept_declaration(
&mut builder,
usize::from(declaration),
field.value,
field.position,
)?;
None
}
IncomingName::Forbidden(name) => {
return Err(FieldError::forbidden(name, field.position));
}
IncomingName::Undeclared(name) => Some(name),
IncomingName::Text(name) => {
(!S::accept(&mut builder, name, field.value, field.position)?).then_some(name)
}
};
if let Some(name) = unclaimed {
if S::REJECTS_UNKNOWN {
return Err(FieldError::unknown(field.position));
}
if let Some(remainder) = remainder.as_deref_mut() {
remainder.extend([FieldRef::new(field.position, name, field.value)]);
}
}
}
S::finish(builder)
}