#[cfg(test)]
mod tests;
use nuts_backend::{Binary, Create, Open, ReceiveHeader, HEADER_MAX_SIZE};
use std::convert::TryInto;
use std::path::Path;
use crate::error::{Error, Result};
use crate::id::Id;
use crate::{read_header, write_header, DirectoryBackend};
const BLOCK_MIN_SIZE: u32 = 512;
#[derive(Clone, Debug)]
pub struct CreateOptions<P: AsRef<Path>> {
path: P,
bsize: u32,
}
impl<P: AsRef<Path>> CreateOptions<P> {
pub fn for_path(path: P) -> Self {
CreateOptions {
path,
bsize: BLOCK_MIN_SIZE,
}
}
pub fn with_bsize(mut self, bsize: u32) -> Self {
self.bsize = bsize;
self
}
fn validate(&self) -> Result<()> {
if self.bsize >= BLOCK_MIN_SIZE {
Ok(())
} else {
Err(Error::InvalidBlockSize(self.bsize))
}
}
}
impl<P: AsRef<Path>> Create<DirectoryBackend<P>> for CreateOptions<P> {
fn settings(&self) -> Settings {
Settings { bsize: self.bsize }
}
fn build(self, header: [u8; HEADER_MAX_SIZE], overwrite: bool) -> Result<DirectoryBackend<P>> {
self.validate()?;
if !overwrite {
let header_path = Id::min().to_pathbuf(self.path.as_ref());
if header_path.exists() {
return Err(Error::Exists);
}
}
write_header(self.path.as_ref(), self.bsize, &header)?;
Ok(DirectoryBackend {
bsize: self.bsize,
path: self.path,
})
}
}
pub struct OpenOptions<P: AsRef<Path>> {
path: P,
}
impl<P: AsRef<Path>> OpenOptions<P> {
pub fn for_path(path: P) -> OpenOptions<P> {
OpenOptions { path }
}
}
impl<P: AsRef<Path>> ReceiveHeader<DirectoryBackend<P>> for OpenOptions<P> {
fn get_header_bytes(&mut self, bytes: &mut [u8; HEADER_MAX_SIZE]) -> Result<()> {
read_header(self.path.as_ref(), bytes)
}
}
impl<P: AsRef<Path>> Open<DirectoryBackend<P>> for OpenOptions<P> {
fn build(self, settings: Settings) -> Result<DirectoryBackend<P>> {
Ok(DirectoryBackend {
bsize: settings.bsize,
path: self.path,
})
}
}
#[derive(Clone, Debug)]
pub struct Settings {
bsize: u32,
}
impl Binary for Settings {
fn from_bytes(bytes: &[u8]) -> Option<Settings> {
match bytes.try_into() {
Ok(bytes) => {
let bsize = u32::from_be_bytes(bytes);
Some(Settings { bsize })
}
Err(_) => None,
}
}
fn as_bytes(&self) -> Vec<u8> {
self.bsize.to_be_bytes().to_vec()
}
}