diff --git a/src/storage/file/hash.rs b/src/storage/file/hash.rs index 68b91b7d..a2f1f96a 100644 --- a/src/storage/file/hash.rs +++ b/src/storage/file/hash.rs @@ -2,12 +2,14 @@ use std::convert::{From, Into}; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::fmt; +use std::hash::Hash; use uuid::Uuid; #[derive(Clone)] #[derive(Debug)] #[derive(PartialEq)] #[derive(Eq)] +#[derive(Hash)] pub struct FileHash { hash: String, } diff --git a/src/storage/file/id.rs b/src/storage/file/id.rs index 36f40cdb..d26b537b 100644 --- a/src/storage/file/id.rs +++ b/src/storage/file/id.rs @@ -2,6 +2,7 @@ use std::convert::{From, Into}; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::fmt; +use std::hash::Hash; use std::path::PathBuf; use std::result::Result; use std::str::FromStr; @@ -12,6 +13,9 @@ use storage::file::id_type::FileIDType; use storage::file::hash::FileHash; #[derive(Clone)] +#[derive(Hash)] +#[derive(Eq)] +#[derive(PartialEq)] pub struct FileID { id: FileHash, id_type: FileIDType, @@ -101,7 +105,7 @@ impl Into for FileID { fn into(self) -> String { let typestr : String = self.id_type.into(); let idstr : String = self.id.into(); - typestr + &idstr[..] + typestr + "-" + &idstr[..] } } diff --git a/src/storage/file/id_type.rs b/src/storage/file/id_type.rs index d13c8bab..474e12a5 100644 --- a/src/storage/file/id_type.rs +++ b/src/storage/file/id_type.rs @@ -1,12 +1,14 @@ use std::convert::{From, Into}; use std::error::Error; use std::str::FromStr; +use std::hash::Hash; #[derive(Debug)] #[derive(Clone)] #[derive(PartialEq)] #[derive(Eq)] // #[derive(Display)] +#[derive(Hash)] pub enum FileIDType { UUID, } diff --git a/src/storage/file/mod.rs b/src/storage/file/mod.rs index 59a2638c..c22b0e5a 100644 --- a/src/storage/file/mod.rs +++ b/src/storage/file/mod.rs @@ -23,130 +23,42 @@ use self::header::data::*; * Internal abstract view on a file. Does not exist on the FS and is just kept * internally until it is written to disk. */ -pub struct File<'a> { - owning_module : &'a Module<'a>, - header : FileHeaderData, - data : String, - id : FileID, +pub struct File { + pub owning_module_name : &'static str, + pub header : FileHeaderData, + pub data : String, + pub id : FileID, } -impl<'a> File<'a> { +impl File { - pub fn new(module: &'a Module<'a>) -> File<'a> { - let f = File { - owning_module: module, - header: FileHeaderData::Null, - data: String::from(""), - id: File::get_new_file_id(), - }; - debug!("Create new File object: {:?}", f); - f + pub fn owner_name(&self) -> &'static str { + self.owning_module_name } - pub fn from_parser_result(module: &'a Module<'a>, id: FileID, header: FileHeaderData, data: String) -> File<'a> { - let f = File { - owning_module: module, - header: header, - data: data, - id: id, - }; - debug!("Create new File object from parser result: {:?}", f); - f + pub fn header(&self) -> &FileHeaderData { + &self.header } - pub fn new_with_header(module: &'a Module<'a>, h: FileHeaderData) -> File<'a> { - let f = File { - owning_module: module, - header: h, - data: String::from(""), - id: File::get_new_file_id(), - }; - debug!("Create new File object with header: {:?}", f); - f + pub fn data(&self) -> &String { + &self.data } - pub fn new_with_data(module: &'a Module<'a>, d: String) -> File<'a> { - let f = File { - owning_module: module, - header: FileHeaderData::Null, - data: d, - id: File::get_new_file_id(), - }; - debug!("Create new File object with data: {:?}", f); - f - } - - pub fn new_with_content(module: &'a Module<'a>, h: FileHeaderData, d: String) -> File<'a> { - let f = File { - owning_module: module, - header: h, - data: d, - id: File::get_new_file_id(), - }; - debug!("Create new File object with content: {:?}", f); - f - } - - /** - * Call editor on the file - * - * Return true if exit code from editor was good (and content was changed), false otherwise. - */ - pub fn edit(rt: &Runtime) { - unimplemented!() - } - - /** - * Call editor on the file contents, but don't include the header inside the editor call. - * - * Return true if exit code from editor was good (and content was changed), false otherwise. - */ - pub fn edit_contents(rt: &Runtime) -> bool { - } - - /** - * Make file persistent. - * - * Retreive store path from the runtime, file id is already available in self. - * - * Return true if action succeeded, false otherwise. - */ - pub fn persist(rt: &Runtime) -> bool { - unimplemented!() - } - - pub fn header(&self) -> FileHeaderData { - self.header.clone() - } - - pub fn data(&self) -> String { - self.data.clone() - } - - pub fn contents(&self) -> (FileHeaderData, String) { + pub fn contents(&self) -> (&FileHeaderData, &String) { (self.header(), self.data()) } - pub fn id(&self) -> FileID { - self.id.clone() - } - - pub fn owner(&self) -> &'a Module<'a> { - self.owning_module + pub fn id(&self) -> &FileID { + &self.id } pub fn matches_with(&self, r: &Regex) -> bool { r.is_match(&self.data[..]) || self.header.matches_with(r) } - fn get_new_file_id() -> FileID { - use uuid::Uuid; - let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string()); - FileID::new(FileIDType::UUID, hash) - } } -impl<'a> Display for File<'a> { +impl Display for File { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, @@ -154,7 +66,7 @@ impl<'a> Display for File<'a> { FileID: '{:?}' Header: '{:?}' Data : '{:?}'", - self.owning_module, + self.owning_module_name, self.header, self.data, self.id); @@ -163,7 +75,7 @@ impl<'a> Display for File<'a> { } -impl<'a> Debug for File<'a> { +impl Debug for File { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { write!(fmt, @@ -171,7 +83,7 @@ impl<'a> Debug for File<'a> { FileID: '{:?}' Header: '{:?}' Data : '{:?}'", - self.owning_module, + self.owning_module_name, self.header, self.data, self.id); diff --git a/src/storage/mod.rs b/src/storage/mod.rs index e51307df..998bba95 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,4 +1,153 @@ +use std::rc::Rc; +use std::cell::RefCell; +use std::collections::HashMap; +use std::fs::File as FSFile; +use std::ops::Deref; +use std::io::Write; + pub mod path; pub mod file; pub mod parser; pub mod json; + +use module::Module; +use runtime::Runtime; +use storage::file::File; +use storage::file::id::FileID; +use storage::file::id_type::FileIDType; +use storage::file::hash::FileHash; +use storage::parser::{FileHeaderParser, Parser, ParserError}; +use storage::file::header::data::FileHeaderData; + +type Cache = HashMap>>; + +pub struct Store { + cache : RefCell, +} + +impl Store { + + pub fn new() -> Store { + Store { + cache: RefCell::new(HashMap::new()), + } + } + + fn put_in_cache(&self, f: File) -> FileID { + let res = f.id().clone(); + self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f))); + res + } + + pub fn new_file(&self, module: &Module) + -> FileID + { + let f = File { + owning_module_name: module.name(), + header: FileHeaderData::Null, + data: String::from(""), + id: self.get_new_file_id(), + }; + + debug!("Create new File object: {:?}", &f); + self.put_in_cache(f) + } + + pub fn new_file_from_parser_result(&self, + module: &Module, + id: FileID, + header: FileHeaderData, + data: String) + -> FileID + { + let f = File { + owning_module_name: module.name(), + header: header, + data: data, + id: id, + }; + debug!("Create new File object from parser result: {:?}", f); + self.put_in_cache(f) + } + + pub fn new_file_with_header(&self, + module: &Module, + h: FileHeaderData) + -> FileID + { + let f = File { + owning_module_name: module.name(), + header: h, + data: String::from(""), + id: self.get_new_file_id(), + }; + debug!("Create new File object with header: {:?}", f); + self.put_in_cache(f) + } + + pub fn new_file_with_data(&self, module: &Module, d: String) + -> FileID + { + let f = File { + owning_module_name: module.name(), + header: FileHeaderData::Null, + data: d, + id: self.get_new_file_id(), + }; + debug!("Create new File object with data: {:?}", f); + self.put_in_cache(f) + } + + pub fn new_file_with_content(&self, + module: &Module, + h: FileHeaderData, + d: String) + -> FileID + { + let f = File { + owning_module_name: module.name(), + header: h, + data: d, + id: self.get_new_file_id(), + }; + debug!("Create new File object with content: {:?}", f); + self.put_in_cache(f) + } + + pub fn persist(&self, + storepath: String, + p: &Parser, + f: Rc>) -> bool + where HP: FileHeaderParser + { + let file = f.deref().borrow(); + let text = p.write(file.contents()); + if text.is_err() { + error!("Error: {}", text.err().unwrap()); + return false; + } + + let path = { + let ids : String = file.id().clone().into(); + format!("{}/{}-{}.imag", storepath, file.owning_module_name, ids) + }; + + FSFile::create(&path).map(|mut fsfile| { + fsfile.write_all(&text.unwrap().clone().into_bytes()[..]) + }).map_err(|writeerr| { + debug!("Could not create file at '{}'", path); + }).and(Ok(true)).unwrap() + } + + pub fn load(&self, id: &FileID) -> Option>> { + debug!("Loading '{:?}'", id); + self.cache.borrow().get(id).cloned() + } + + fn get_new_file_id(&self) -> FileID { + use uuid::Uuid; + let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string()); + FileID::new(FileIDType::UUID, hash) + } + +} diff --git a/src/storage/parser.rs b/src/storage/parser.rs index 266f6a3d..a3bbf832 100644 --- a/src/storage/parser.rs +++ b/src/storage/parser.rs @@ -122,7 +122,7 @@ impl Parser { Ok((h_parseres, data.unwrap_or(String::new()))) } - pub fn write(&self, tpl : (FileHeaderData, String)) -> Result { + pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result { debug!("Parsing internal datastructure to String"); let (header, data) = tpl; let h_text = try!(self.headerp.write(&header)); diff --git a/src/ui/file.rs b/src/ui/file.rs index 625eb43e..114e5c83 100644 --- a/src/ui/file.rs +++ b/src/ui/file.rs @@ -14,7 +14,7 @@ pub trait FilePrinter { /* * Print a list of files */ - fn print_files<'a, I: Iterator>>(&self, files: I) { + fn print_files>(&self, files: I) { for file in files { self.print_file(&file); } @@ -88,7 +88,7 @@ impl FilePrinter for TablePrinter { self.sp.print_file(f); } - fn print_files<'a, I: Iterator>>(&self, files: I) { + fn print_files>(&self, files: I) { use prettytable::Table; use prettytable::row::Row; use prettytable::cell::Cell; @@ -103,9 +103,9 @@ impl FilePrinter for TablePrinter { debug!("Printing file: {:?}", file); i += 1; let cell_i = Cell::new(&format!("{}", i)[..]); - let cell_o = Cell::new(&format!("{}", file.owner().name())[..]); + let cell_o = Cell::new(&format!("{}", file.owner_name())[..]); - let id : String = file.id().into(); + let id : String = file.id().clone().into(); let cell_id = Cell::new(&id[..]); let row = Row::new(vec![cell_i, cell_o, cell_id]); tab.add_row(row);