#![doc = include_str!("../README.md")]
#![cfg_attr(target_family = "wasm", feature(wasi_ext))]
mod file_ext;
pub mod page_no;
use file_ext::FileExt;
use std::fmt;
use std::fs::File;
use std::io::{ErrorKind, Result};
use std::sync::atomic::{AtomicU64, Ordering};
pub struct Pages<const SIZE: usize> {
len: AtomicU64,
pub file: File,
}
impl<const SIZE: usize> Pages<SIZE> {
pub fn open(file: File) -> Result<Self> {
let block_size = SIZE as u64;
let file_len = file.metadata()?.len();
if file_len % block_size != 0 {
return Err(ErrorKind::InvalidData.into());
}
Ok(Self {
file,
len: (file_len / block_size).into(),
})
}
pub fn read(&self, num: u64) -> Result<[u8; SIZE]> {
debug_assert!(num < self.len() as u64);
let mut buf = [0; SIZE];
self.file.read_exact_at(&mut buf, SIZE as u64 * num)?;
Ok(buf)
}
#[inline]
pub fn write(&self, num: u64, buf: [u8; SIZE]) -> Result<()> {
debug_assert!(num < self.len() as u64);
self.file.write_all_at(&buf, SIZE as u64 * num)
}
pub fn alloc(&self, count: u64) -> Result<u64> {
let old_len = self.len.fetch_add(count, Ordering::SeqCst);
self.file.set_len(SIZE as u64 * (old_len + count))?;
Ok(old_len)
}
pub fn create(&self, buf: [u8; SIZE]) -> Result<u64> {
let num = self.len.fetch_add(1, Ordering::SeqCst);
self.write(num, buf)?;
Ok(num)
}
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 {
self.len.load(Ordering::SeqCst)
}
#[inline]
pub fn set_len(&self, len: u64) -> Result<()> {
self.len.store(len, Ordering::SeqCst);
self.file.set_len(SIZE as u64 * len)
}
}
impl<const SIZE: usize> fmt::Debug for Pages<SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pages")
.field("len", &self.len)
.field("block size", &SIZE)
.finish()
}
}