use std::io::{Read, Seek};
use std::marker::PhantomData;
use crate::error::{TychoError, TychoResult};
use crate::partial::reader::{PartialPointer, PartialReader};
pub trait PartialContainerType {
type ItemType;
type ItemParam;
fn read_item<R: Read + Seek>(reader: &mut PartialReader<R>, param: &Self::ItemParam) -> TychoResult<Self::ItemType>;
}
#[derive(Debug, Clone)]
pub struct PartialContainer<T: PartialContainerType> {
pub pointer: PartialPointer,
pub head: u64,
pub param: T::ItemParam,
_phantom: PhantomData<T>
}
impl<T: PartialContainerType> PartialContainer<T> {
pub(crate) fn new(pointer: PartialPointer, head: u64, param: T::ItemParam) -> Self {
PartialContainer { pointer, head, _phantom: Default::default(), param }
}
pub(crate) fn empty(pointer: PartialPointer, param: T::ItemParam) -> Self {
PartialContainer { pointer, head: 0, _phantom: Default::default(), param }
}
pub(crate) fn next_item<R: Read + Seek>(&mut self, reader: &mut PartialReader<R>) -> TychoResult<Option<T::ItemType>> {
#[cfg(feature="partial_state")]
if self.pointer.ident != reader.ident {
return Err(TychoError::OutdatedPointer)
}
if self.head == self.pointer.size {
return Ok(None);
}
let top = reader.pointer.clone();
reader.jump(&(self.pointer.pos + self.head))?;
let head_start = reader.pointer;
let item = T::read_item(reader, &self.param)?;
self.head += reader.pointer - head_start;
reader.jump(&top)?;
Ok(Some(item))
}
pub fn finished(&self) -> bool { self.head == self.pointer.size }
pub fn next<R: Read + Seek>(&mut self, reader: &mut PartialReader<R>) -> TychoResult<Option<T::ItemType>> {
self.next_item(reader)
}
pub fn iter<'x, R: Read + Seek>(&'x mut self, reader: &'x mut PartialReader<R>) -> PartialContainerIterator<'x, T, R> {
PartialContainerIterator::new(self, reader)
}
pub fn collect<R: Read + Seek>(&mut self, reader: &mut PartialReader<R>) -> TychoResult<Vec<T::ItemType>> {
let mut items = Vec::new();
while let Some(item) = self.next_item(reader)? {
items.push(item);
}
Ok(items)
}
pub fn top(&mut self) {
self.head = 0;
}
}
pub struct PartialContainerIterator<'x, T: PartialContainerType, R: Read + Seek>(
&'x mut PartialContainer<T>,
&'x mut PartialReader<R>
);
impl<'x, T: PartialContainerType, R: Read + Seek> PartialContainerIterator<'x, T, R> {
pub fn new(
container: &'x mut PartialContainer<T>,
reader: &'x mut PartialReader<R>
) -> PartialContainerIterator<'x, T, R> {
Self {
0: container,
1: reader
}
}
}
impl<'x, T: PartialContainerType, R: Read + Seek> Iterator for PartialContainerIterator<'x, T, R> {
type Item = T::ItemType;
fn next(&mut self) -> Option<Self::Item> {
self.0.next_item(self.1).ok()?
}
}