use std::fmt;
use std::iter::FusedIterator;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct PartHead<'a> {
section: &'a [u8],
}
impl<'a> PartHead<'a> {
pub(crate) fn new(section: &'a [u8]) -> Self {
Self { section }
}
pub fn fields(&self) -> PartFields<'a> {
PartFields { rest: self.section }
}
pub fn len(&self) -> usize {
self.fields().count()
}
pub fn is_empty(&self) -> bool {
self.section.is_empty()
}
pub fn as_bytes(&self) -> &'a [u8] {
self.section
}
}
impl fmt::Debug for PartHead<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let fields = self
.fields()
.map(|(name, value)| (name, format!("<{} bytes>", value.len())));
formatter
.debug_struct("PartHead")
.field("fields", &fields.collect::<Vec<_>>())
.finish()
}
}
impl<'a> IntoIterator for PartHead<'a> {
type Item = (&'a str, &'a [u8]);
type IntoIter = PartFields<'a>;
fn into_iter(self) -> Self::IntoIter {
self.fields()
}
}
#[derive(Clone)]
pub struct PartFields<'a> {
rest: &'a [u8],
}
impl fmt::Debug for PartFields<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("PartFields")
.field("remaining", &format_args!("<{} bytes>", self.rest.len()))
.finish()
}
}
impl<'a> Iterator for PartFields<'a> {
type Item = (&'a str, &'a [u8]);
fn next(&mut self) -> Option<Self::Item> {
let end = memchr::memmem::find(self.rest, b"\r\n")?;
let line = &self.rest[..end];
self.rest = &self.rest[end + 2..];
let colon = memchr::memchr(b':', line).expect("a checked header line has a colon");
let name = std::str::from_utf8(&line[..colon]).expect("a checked field name is ASCII");
Some((name, base_message::trim_whitespace(&line[colon + 1..])))
}
}
impl FusedIterator for PartFields<'_> {}