use gulkana;
use std::fmt;
use serde::{Serialize};
pub enum FSError{
KeyAllreadyPresent,
KeyNotFound,
NodeNotLink,
NodeNotData,
PathNotPresent,
FileError,
SerializeError,
}
impl Into<String> for FSError{
fn into(self)->String{
match self{
FSError::KeyAllreadyPresent=>"KeyAllreadyPresent".to_string(),
FSError::KeyNotFound=>"KeyNotFound".to_string(),
FSError::NodeNotLink=>"NodeNotLink".to_string(),
FSError::NodeNotData=>"NodeNotData".to_string(),
FSError::PathNotPresent=>"PathNotPresent".to_string(),
FSError::FileError=>"File Error".to_string(),
FSError::SerializeError=>"Error when Serializing to String".to_string(),
}
}
}
impl fmt::Display for FSError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}",match self{
FSError::KeyAllreadyPresent=>"KeyAllreadyPresent".to_string(),
FSError::KeyNotFound=>"KeyNotFound".to_string(),
FSError::NodeNotLink=>"NodeNotLink".to_string(),
FSError::NodeNotData=>"NodeNotData".to_string(),
FSError::PathNotPresent=>"PathNotPresent".to_string(),
FSError::FileError=>"File Error".to_string(),
FSError::SerializeError=>"Error when Serializing to String".to_string(),
})
}
}
impl From<gulkana::DBOperationError> for FSError{
fn from(error:gulkana::DBOperationError)->Self{
match error{
gulkana::DBOperationError::KeyAllreadyPresent
=>FSError::KeyAllreadyPresent,
gulkana::DBOperationError::KeyNotFound
=>FSError::KeyNotFound,
gulkana::DBOperationError::NodeNotLink
=>FSError::NodeNotLink,
gulkana::DBOperationError::NodeNotData
=>FSError::NodeNotData,
gulkana::DBOperationError::SerializeError
=>FSError::SerializeError,
gulkana::DBOperationError::FSError
=>FSError::FileError,
}
}
}
impl From<std::io::Error> for FSError{
fn from(error: std::io::Error)->Self{
match error{
_ =>FSError::FileError,
}
}
}
impl From<gulkana::SerializeError> for FSError{
fn from(error: gulkana::SerializeError)->Self{
match error{
_ =>FSError::SerializeError,
}
}
}
type KeyType=String;
#[derive(Clone)]
pub struct Database<DataType:std::clone::Clone+Serialize,LinkLabel:std::clone::Clone+Serialize>{
db:gulkana::DataStructure<String,DataType,LinkLabel>,
}
pub struct ChildIter<'a,DataType:std::clone::Clone+Serialize,
LinkLabel:std::clone::Clone+Serialize>{
db:&'a Database<DataType,LinkLabel>,
iter:std::slice::Iter<'a,KeyType>
}
impl<'a,DataType:std::clone::Clone+Serialize,LinkLabel:std::clone::Clone+Serialize>
Iterator for ChildIter<'a,DataType,LinkLabel>{
type Item = (& 'a KeyType,DataType);
fn next(&mut self)->Option<Self::Item>{
let index = self.iter.next()?;
let res = self.db.get(index);
if res.is_ok(){
return Some((index,res.ok().unwrap()));
}else{
return None;
}
}
}
impl<DataType:std::clone::Clone+Serialize,LinkLabel:std::clone::Clone+Serialize>
Database<DataType,LinkLabel>{
pub fn insert(&mut self,input: &DataType,parent:&KeyType,key:&KeyType)->Result<KeyType,FSError>{
if self.db.contains(parent){
self.db.insert(key,input.clone())?;
self.db.append_links(parent,key)?;
return Ok(key.clone());
}else{
return Err(FSError::KeyNotFound);
}
}
pub fn overwrite(&mut self,key:&KeyType,input: &DataType)->Result<KeyType,FSError>{
self.db.set_data(key,input)?;
Ok(key.clone())
}
pub fn get(&self,key:&KeyType)->Result<DataType,FSError>{
let h = self.db.get(key)?;
return Ok(h.clone());
}
pub fn make_dir(&mut self,label:LinkLabel,key:&KeyType)->Result<KeyType,FSError>{
self.db.insert_link(key,&vec![],label)?;
return Ok(key.clone());
}
pub fn make_dir_children(&mut self,key:&KeyType,label:LinkLabel,children:&std::vec::Vec<KeyType>)->Result<KeyType,FSError>{
self.db.insert_link(key,children,label)?;
return Ok(key.clone());
}
pub fn get_node_children(&self,key:KeyType)->Result<&Vec<KeyType>,FSError>{
let link = self.db.get_links(&key)?;
return Ok(link);
}
pub fn iter_children(&self,key:&KeyType)->Result<ChildIter<DataType,LinkLabel>,FSError>{
Ok(ChildIter{
db:self,
iter:self.db.get_links(key)?.iter()
})
}
}
pub fn new<DataType:std::clone::Clone+Serialize,LinkLabel:std::clone::Clone+Serialize>
(backing:Option<String>,dir_label:LinkLabel)->Result<Database<DataType,LinkLabel>,FSError>{
let mut db = Database{
db:gulkana::new_datastructure(backing),
};
db.make_dir(dir_label,&"/".to_string())?;
return Ok(db);
}
#[cfg(test)]
mod tests{
use super::*;
#[derive(Clone,Serialize)]
enum DB{
Directory,
}
#[derive(Clone,Serialize,PartialEq)]
struct DBEnt{
f:u32,
}
#[test]
#[allow(unused_must_use)]
fn insert(){
let in_db = DBEnt{
f:1,
};
let mut db = new(None,DB::Directory).ok().unwrap();
let key_res = db.insert(&in_db.clone(),&"/".to_string(),&"foo".to_string()).ok().unwrap();
let out = db.get(&key_res);
assert!(in_db==out.ok().unwrap());
}
#[test]
#[allow(unused_must_use)]
fn overwrite(){
let in_db = DBEnt{
f:1,
};
let mut db = new(None,DB::Directory).ok().unwrap();
let key_res = db.insert(&in_db.clone(),&"/".to_string(),&"foo".to_string()).ok().unwrap();
let ov = DBEnt{
f:2,
};
db.overwrite(&"foo".to_string(),&ov.clone());
let out = db.get(&key_res);
assert!(ov==out.ok().unwrap());
}
#[test]
fn get_root_children(){
let mut db = new(None,DB::Directory).ok().unwrap();
let in_db = DBEnt{
f:0,
};
let key = db.insert(&in_db,&"/".to_string(),&"foo".to_string()).ok().unwrap();
let dir = db.make_dir(DB::Directory,&"foos".to_string()).ok().unwrap();
let key2 = db.insert(&in_db,&dir,&"foossa".to_string()).ok().unwrap();
let v = db.get_node_children("/".to_string()).ok().unwrap();
for i in v{
assert!(i==&key);
}
let v2 = db.get_node_children(dir).ok().unwrap();
for i in v2{
assert!(i==&key2);
}
}
#[test]
fn iterate_root(){
let mut db = new(None,DB::Directory).ok().unwrap();
let key = db.insert(&DBEnt{f:0},&"/".to_string(),&"file".to_string()).ok().unwrap();
for (key_t,data) in db.iter_children(&"/".to_string()).ok().unwrap(){
assert!(key_t==&key&&data.f==0);
}
}
#[test]
fn mass_insert(){
let in_db = DBEnt{
f:3,
};
let mut db = new(None,DB::Directory).ok().unwrap();
for i in 1..10000{
let key_res = db.insert(&in_db.clone(),&"/".to_string(),&format!("{}",i));
assert!(key_res.is_ok());
}
}
}