use page::{Page, PAGE_SIZE, PAGE_PAYLOAD_SIZE};
use pagedfile::PagedFile;
use error::HammersbaldError;
use pref::PRef;
pub const FIRST_PAGE_HEAD:usize = 28;
pub const BUCKET_SIZE: usize = 6;
pub const BUCKETS_PER_PAGE:usize = PAGE_PAYLOAD_SIZE/BUCKET_SIZE;
pub const BUCKETS_FIRST_PAGE:usize = (PAGE_PAYLOAD_SIZE - FIRST_PAGE_HEAD)/BUCKET_SIZE;
pub struct TableFile {
file: Box<PagedFile>
}
impl TableFile {
pub fn new (file: Box<PagedFile>) -> Result<TableFile, HammersbaldError> {
Ok(TableFile {file})
}
pub fn table_offset (bucket: usize) -> PRef {
if (bucket as u64) < BUCKETS_FIRST_PAGE as u64 {
PRef::from((bucket * BUCKET_SIZE + FIRST_PAGE_HEAD) as u64)
}
else {
PRef::from(
((bucket - BUCKETS_FIRST_PAGE)/BUCKETS_PER_PAGE + 1) as u64 * PAGE_SIZE as u64
+ (bucket % BUCKETS_PER_PAGE) as u64 * BUCKET_SIZE as u64)
}
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item=PRef> +'a {
BucketIterator{file: self, n:0}
}
}
impl PagedFile for TableFile {
fn flush(&mut self) -> Result<(), HammersbaldError> {
self.file.flush()
}
fn len(&self) -> Result<u64, HammersbaldError> {
self.file.len()
}
fn truncate(&mut self, new_len: u64) -> Result<(), HammersbaldError> {
self.file.truncate(new_len)
}
fn sync(&self) -> Result<(), HammersbaldError> {
self.file.sync()
}
fn shutdown (&mut self) {}
fn read_page(&self, pref: PRef) -> Result<Option<Page>, HammersbaldError> {
if let Some(page) = self.file.read_page(pref)? {
if page.pref() != pref {
return Err(HammersbaldError::Corrupted(format!("table page {} does not have the pref of its position", pref)));
}
return Ok(Some(page));
}
Ok(None)
}
fn append_page(&mut self, _: Page) -> Result<(), HammersbaldError> {
unimplemented!()
}
fn update_page(&mut self, page: Page) -> Result<u64, HammersbaldError> {
self.file.update_page(page)
}
}
struct BucketIterator<'a> {
file: &'a TableFile,
n: usize
}
impl<'a> Iterator for BucketIterator<'a> {
type Item = PRef;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
let table_offset = TableFile::table_offset(self.n);
if let Ok(Some(page)) = self.file.read_page(table_offset.this_page()) {
self.n += 1;
return Some(page.read_pref(table_offset.in_page_pos()))
}
None
}
}