Storage development documentation IMPORTANT * Should be renamed Storage is too long. Rust variables basically views between 3 and 5-6 characters. Vec, Box, i32, u32, HashMap, HashSet, ... e.g.: Bag could be fine. Name ideas: * Storage| * Store | * Strg | * Bag | (L) * * * * * * Bg | * Dal | * Fd | * Data | * Dt | * Dta | * Peel | (L) * * * * Shell | * Shl | * Rind | * Layer | * Sack | * Pack | (L) * * * * * * Pop | * Pod Issues to solve =============== * Delete item? Delete item from FS and from Memory. Vec item could be removed, but a single Pop? Example impl Vec> { pub fn remove_item_by_id(&mut self, id: I) {..} } * Move item between storages? Move one Pack from one storage to another one, when both of them has the same type T. This should be a kind of create new and remove the old one. * Single file storage Should be able to use a single file as a storage; in cases when we do not need any vector of the same type files. E.g.: config files, or helper files like let mut units: Pack = Pack::load_or_init("path")?; * Issue with single file storage How can we use a default implementation when the file does not exist yet? I mean we have a user conig, but we have a new user. * Pack::from_storage(&storageA)?; * Schema versions? Migrate easily and safely from one schema to a new one. Using easy development process to be sure, a schema has a schema backup history, so it can be up from older shcema automatically. In the recent version we use a kind of ~~ load_from() ~~ method, but it is not soo easy and not soo clear to use. * OBJECT ID any type? Not just &str * OBJECT ID automatic generation * Multy THREAD? Prevent racecondition * Pack as a struct field? struct Repository { #[path="/config"] config: Pack, #[path="/users"] users: Vec>, #[path="/issues"] issues: Vec>, .. } impl Repository { pub fn new(id: &str) -> PackResult { let storage = Storage::load_or_init("data/repositories/", id); Repository { config: storage.file_from("config")?, users: storage.folder_from("./users/")?, issues: storage.folder_from("./folder")? } } } Ideas A few ideas about the required design: struct Pack { data: T, path: &'static str } impl Deref for Pack {..} | | *--- Implementing deref() means we can access the inner DATA READ ONLY. struct Guard<'a, T> { data: &'a mut T, path: &'static str } impl<'a, T> Deref for Guard<'a, T> {..} impl<'a, T> DerefMut for Guard<'a, T> {..} | | *--- Implementing deref_mut() means we have acces for inner DATA as MUTABLE. impl<'a, T> Drop for Guard<'a, T> {..} | | *--- Drop Guard<'a, T> automatically, and perform File save on DATA OBJECT struct VecPack { data: Vec>, path: &'static str } Init a Pack OBJECT Pack should be inited by loading from path, or create and save a new copy by its storage. e.g.: let config: Pack = Pack::load_from_path("path")?; let products: Vec> = Pack::load_from_path("path")?; | | *--- and then --> products.add_new(new_product)?; let config: Pack = Pack::load_or_init("path")?; Pack variants Pack PackVec --- Vec> HashMap> let mut m = Storage::new("data"); m.add(&mut Vec>, T); let products: Storage> = Storage::load_or_init(..)?; products.push(new_product1)?; products.push(new_product2)?; let mut products: PackVec = PackVec::new("/data/products"); products.push(new_product1)?; products.push(new_product2)?; Pack + deref(&self) -> &T + deref_mut(&mut self) -> &mut T + save(&self) -> PackResult<()> + update(&mut self, f: FnMut) -> R + get(&self, f: Fn) -> R + map(&self, f: F) -> R :: load(path: &'static str) -> PackResult> :: load_or_init(path: &'static str) -> PackResult> fn try_load() -> PackResult> where T: Serialize + Deserialize + TryFrom ------------- 1. Try open file 2. Try read file content to buffer 3. Try deserialize buffer to the given type | | *-- If SUCCESS => returns the Pack | *-- If ERROR => try From pub trait TryLoad where T: From

P: Deserialize { fn

try_load() -> PackResult

} save() ------------- 1. Try serialize OBJECT DATA 2. Try write_all to the given path VecPack + deref(&self) -> &Vec> It's like an iter(). ! deref_mut(&mut self) -> &mut Vec> Ezt lehet nem kellene engedni csak a VecPack apin keresztül Helyette iter_mut() + push(&mut self, T) -> PackResult Or add().. Add a new elem into the VecPack + check_id_available(&self, id: ID) -> bool + push_with_id(&mut self, T, id: ID) -> PackResult<()> + get_by_id(id: I) -> Option<&Pack> / Option<&T> + get_mut_by_id(id: I) -> Option<&mut Pack> / Option> + iter() -> &Vec> + into_iter(&mut self) -> &mut Vec> + move(&mut self, index: I, to: D) -> PackResult<()> + remove(&mut self, index: I) -> PackResult + get_path(&self) -> Path let struct Repository { id: String, config: Pack, users: PackVec, products: PackVec } let mut repositories: Pack> = Pack::load_or_init("/data/repositores")?; let mut repos: Vec = repositores .iter() .map(|r| i.init()) .collect(); Pack methods * save(&self) -> PackResult <----- result Self is not sure * let product_storage: Storage = Storage::load_or_init("/products")?; let p1 = product_storage.new(Product::new())?; let mut products: Vec> = Vec::new(); products.push(p1); Storage>> Schema Version Management (SVM) We need an easy to use solution to manage schema updates and data migration with ZERO ERROR. trait TryFrom { type From: TryFrom; fn try_from() -> PackResult {} }