use crate::*;
use std::path::{Path, PathBuf};
use std::fs;
#[macro_export]
macro_rules! write_container {
(($container:expr) $($item:ident)?$(($obj:expr))? = $func:ident($value:expr)) => {(|| {
let container = &$container;
$(LazyData::$func(container.data_writer(stringify!($item))?, $value)?;)?
$(LazyData::$func(container.data_writer($obj)?, $value)?;)?
Result::<(), LDBError>::Ok(())
})()};
(($container:expr) /$($($con:ident)?$(($can:expr))?)/ *::$($item:ident)?$(($obj:expr))? = $func:ident($value:expr)) => {(|| {
let mut container = &mut $container;
$({
let con = $(stringify!($con))?$($can)?;
container = match container.read_container(con) {
Ok(x) => x,
Err(LDBError::DirNotFound(_)) => container.new_container(con)?,
Err(e) => return Err(e),
}
};)*
$(LazyData::$func(container.data_writer(stringify!($item))?, $value)?;)?
$(LazyData::$func(container.data_writer($obj)?, $value)?;)?
Result::<(), LDBError>::Ok(())
})()}
}
#[macro_export]
macro_rules! search_container {
(($container:expr) /$($($con:ident)?$(($can:expr))?)/ *) => {(|| {
let container = &$container;
$(
$(let container = container.read_container(stringify!($con))?;)?
$(let container = container.read_container($can)?;)?
)*
let result: Result<LazyContainer, LDBError> = Ok(container);
result
})()};
(($container:expr) /$($($con:ident)?$(($can:expr))?)/ *::$($item:ident)?$(($obj:expr))?) => {(|| {
let container = search_container!(($container) /$($($con)?$(($can))?)/ *)?;
$(let result: Result<LazyData, LDBError> = container.read_data(stringify!($item));)?
$(let result: Result<LazyData, LDBError> = container.read_data($obj);)?
result
})()};
(($container:expr) $($item:ident)?$(($obj:expr))?) => {(|| {
let container = &$container;
$(let result: Result<LazyData, LDBError> = container.read_data(stringify!($item));)?
$(let result: Result<LazyData, LDBError> = container.read_data($obj);)?
result
})()};
}
pub struct LazyContainer {
path: PathBuf,
}
impl LazyContainer {
pub fn init(path: impl AsRef<Path>) -> Result<Self, std::io::Error> {
let path = path.as_ref();
if !path.is_dir() { fs::create_dir_all(path)? };
Ok(Self {
path: path.to_path_buf(),
})
}
pub fn load(path: impl AsRef<Path>) -> Result<Self, LDBError> {
let path = path.as_ref().to_path_buf();
if !path.is_dir() { return Err(LDBError::DirNotFound(path)) };
Ok(Self {
path,
})
}
pub fn data_writer(&self, key: impl AsRef<Path>) -> Result<FileWrapper, LDBError> {
let path = self.path.join(key);
if path.is_file() { let _ = fs::remove_file(&path); }; let file = unwrap_result!((fs::File::create(path)) err => LDBError::IOError(err));
Ok(FileWrapper::new_writer(file))
}
pub fn new_container(&self, key: impl AsRef<Path>) -> Result<LazyContainer, LDBError> {
let path = self.path.join(&key);
if path.is_dir() { unwrap_result!((fs::remove_dir_all(&path)) err => LDBError::IOError(err)) }; Ok(unwrap_result!((LazyContainer::init(path)) err => LDBError::IOError(err)))
}
pub fn child_container(&self, key: impl AsRef<Path>) -> Result<LazyContainer, LDBError> {
let path = self.path.join(&key);
if path.is_dir() { return self.read_container(key) }; Ok(unwrap_result!((LazyContainer::init(path)) err => LDBError::IOError(err)))
}
pub fn read_data(&self, key: impl AsRef<Path>) -> Result<LazyData, LDBError> {
let path = self.path.join(key);
if !path.is_file() { return Err(LDBError::FileNotFound(path)) };
LazyData::load(path)
}
pub fn read_container(&self, key: impl AsRef<Path>) -> Result<LazyContainer, LDBError> {
let path = self.path.join(key);
if !path.is_dir() { return Err(LDBError::DirNotFound(path)) };
LazyContainer::load(path)
}
pub fn remove(&self, key: impl AsRef<Path>) -> Result<(), std::io::Error> {
let path = self.path.join(key);
if path.is_dir() {
fs::remove_dir_all(path)
} else {
fs::remove_file(path)
}
}
pub fn wipe(&self) -> Result<(), std::io::Error> {
fs::remove_dir_all(&self.path)?;
fs::create_dir_all(&self.path)
}
#[inline]
pub fn path(&self) -> &Path {
&self.path
}
}