use core::fmt;
use core::iter::FusedIterator;
use crate::decode::Decoder;
use crate::error::Error;
use crate::model::Cookie;
pub fn cookies(input: &[u8]) -> Result<Cookies<'_>, Error> {
let mut decoder = Decoder::new(input);
decoder.signature()?;
let pages_left = decoder.page_count()?;
decoder.skip_page_size_table(pages_left)?;
Ok(Cookies {
decoder,
pages_left,
left_in_page: 0,
finished: false,
})
}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Cookies<'a> {
decoder: Decoder<'a>,
pages_left: u32,
left_in_page: u32,
finished: bool,
}
impl Cookies<'_> {
fn read_page_header(&mut self) -> Result<u32, Error> {
self.decoder.page_tag()?;
let count = self.decoder.cookie_count()?;
self.decoder.skip_cookie_offset_table(count)?;
self.decoder.page_end()?;
Ok(count)
}
}
impl Iterator for Cookies<'_> {
type Item = Result<Cookie, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
loop {
if self.left_in_page > 0 {
self.left_in_page -= 1;
let result = self.decoder.cookie();
if result.is_err() {
self.finished = true;
}
return Some(result);
}
if self.pages_left > 0 {
self.pages_left -= 1;
match self.read_page_header() {
Ok(count) => self.left_in_page = count,
Err(error) => {
self.finished = true;
return Some(Err(error));
}
}
continue;
}
self.finished = true;
return match self.decoder.checksum() {
Ok(_) => None,
Err(error) => Some(Err(error)),
};
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.finished {
(0, Some(0))
} else {
(0, None)
}
}
}
impl FusedIterator for Cookies<'_> {}
impl fmt::Debug for Cookies<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Cookies")
.field("pages_left", &self.pages_left)
.field("left_in_page", &self.left_in_page)
.field("finished", &self.finished)
.finish_non_exhaustive()
}
}