#![cfg_attr(feature = "nightly", deny(missing_docs))]
#![cfg_attr(feature = "nightly", feature(external_doc))]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![cfg_attr(test, deny(warnings))]
mod iter;
mod page;
pub use crate::iter::Iter;
pub use crate::page::Page;
use std::fs::File;
use std::io;
use std::io::Read;
#[derive(Debug)]
pub struct Pager {
pages: Vec<Option<Page>>,
page_size: usize,
}
impl Pager {
#[inline]
pub fn new(page_size: usize) -> Self {
Pager {
page_size,
pages: Vec::new(),
}
}
#[inline]
pub fn from_file(
file: &mut File,
page_size: usize,
offset: Option<usize>,
) -> Result<Self, io::Error> {
let offset = offset.unwrap_or(0);
let len = file.metadata()?.len() as usize - offset;
if len % page_size != 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"<memory-pager>: Reader len ({}) is not a multiple of {}",
len, page_size
),
));
}
let page_count = len / page_size;
let mut pages = Vec::with_capacity(page_count);
let mut buf = vec![0; page_size];
for index in 0..page_count {
let bytes_read = file.read(&mut buf)?;
if bytes_read < page_size {
break;
}
if is_zeroed(&buf) {
pages.push(None);
} else {
pages.push(Some(Page::new(index, buf)));
buf = vec![0; page_size];
}
}
Ok(Self { pages, page_size })
}
#[inline]
pub fn get_mut_or_alloc(&mut self, page_num: usize) -> &mut Page {
if page_num >= self.pages.len() {
self.grow_pages(page_num);
}
if self.pages[page_num].is_none() {
let buf = vec![0; self.page_size];
let page = Page::new(page_num, buf);
self.pages[page_num] = Some(page);
}
self.pages[page_num].as_mut().unwrap()
}
#[inline]
pub fn get(&self, page_num: usize) -> Option<&Page> {
self.pages.get(page_num).and_then(|page| page.as_ref())
}
#[inline]
pub fn get_mut(&mut self, page_num: usize) -> Option<&mut Page> {
self.pages.get_mut(page_num).and_then(|page| page.as_mut())
}
#[inline]
fn grow_pages(&mut self, index: usize) {
self.pages.resize(index + 1, None);
}
#[inline]
pub fn len(&self) -> usize {
self.pages.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.pages.is_empty()
}
#[inline]
pub fn page_size(&self) -> usize {
self.page_size
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter::new(self)
}
}
impl Default for Pager {
fn default() -> Self {
Pager::new(1024)
}
}
#[inline]
fn is_zeroed(vec: &[u8]) -> bool {
for byte in vec {
if *byte != 0 {
return false;
}
}
true
}