use std::{borrow::Cow, io::{Read, Seek, Write}};
use crate::{base::layer::get_u64, errors::Error};
use super::{Section, REWIND_IDX};
#[derive(Debug)]
pub enum Mapper<'l> {
Heap {
write_cursor: (u64, usize),
mapper: Vec<Section<'l>>,
},
Disk,
}
pub struct MapperIter<'l, Stream: Write + Read + Seek> {
mapper: &'l Mapper<'l>,
stream: &'l mut Stream,
size: u64,
idx: usize,
cursor: u64,
}
impl<'l> Default for Mapper<'l> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<'l> Mapper<'l> {
#[inline]
pub fn new() -> Self {
Self::Heap {
write_cursor: (0, 0),
mapper: Vec::new(),
}
}
#[inline]
pub fn get_writer(&mut self) -> Result<(&mut Vec<Section<'l>>, &mut (u64, usize)), Error> {
if let Self::Heap { write_cursor, mapper } = self {
Ok((mapper, write_cursor))
} else {
Err(Error::ReadOnly)
}
}
pub fn iter<'a, Stream: Read + Write + Seek>(&'a self, stream: &'a mut Stream, size: u64, cursor: u64) -> Result<MapperIter<'a, Stream>, Error> {
stream.seek(std::io::SeekFrom::Start(cursor))?;
Ok(MapperIter {
mapper: self,
stream,
size,
idx: 0,
cursor: cursor - REWIND_IDX,
})
}
}
macro_rules! optres {
($expr:expr) => {
match $expr {
Ok(x) => x,
Err(e) => return Some(Err(e.into())),
}
}
}
impl<'l, Stream: Write + Read + Seek> Iterator for MapperIter<'l, Stream> {
type Item = Result<Section<'l>, Error>;
fn next(&mut self) -> Option<Self::Item> { Some(Ok(match self.mapper {
Mapper::Heap { mapper, .. } => {
if self.idx == mapper.len() { return None };
let out = mapper[self.idx].clone();
self.idx += 1;
out
},
Mapper::Disk => {
if self.cursor == self.size { return None };
let mut buffer = [0u8; (u64::BITS as usize/8) * 2]; match self.stream.read_exact(&mut buffer) {
Ok(_) => (),
Err(_) => return Some(Err(Error::DBCorrupt(Box::new(Error::InvalidLayer)))),
}
let bounds = optres!(get_u64(&buffer, 0..8))..optres!(get_u64(&buffer, 8..16));
let size = if let Some(x) = bounds.end.checked_sub(bounds.start) { x } else {return Some(Err(Error::DBCorrupt(Box::new(Error::InvalidLayer)))) };
let mut data = vec![0u8; size as usize];
optres!(self.stream.read_exact(&mut data));
self.cursor += size;
(bounds, Cow::Owned(data))
},
}))
}
}