diff --git a/Cargo.lock b/Cargo.lock index 94ebd99c0..c3c518c8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "dekoder" version = "0.0.1" dependencies = [ + "glob", + "hashbrown", "tar", ] @@ -92,6 +94,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "hashbrown" version = "0.14.0" diff --git a/crates/dekoder/Cargo.toml b/crates/dekoder/Cargo.toml index f5c585a53..1857a048d 100644 --- a/crates/dekoder/Cargo.toml +++ b/crates/dekoder/Cargo.toml @@ -21,3 +21,5 @@ crate-type = ["cdylib"] [dependencies] tar = "0.4.41" +hashbrown = "0.14" +glob = "0.3.1" diff --git a/crates/dekoder/src/lib.rs b/crates/dekoder/src/lib.rs index 317d592a1..d4028d1c7 100644 --- a/crates/dekoder/src/lib.rs +++ b/crates/dekoder/src/lib.rs @@ -1,9 +1,40 @@ //! eko output reader. +use glob::glob; +use hashbrown::HashMap; use std::fs::remove_dir_all; use std::fs::File; use std::io::BufWriter; use std::path::PathBuf; +const HEADER_EXT: &'static str = "*.yaml"; +struct Inventory { + /// Working directory + path: PathBuf, + /// Available items + keys: HashMap, +} +impl Inventory { + /// Load all available entries + pub fn load_keys(&mut self) { + for entry in glob(self.path.join(HEADER_EXT.to_owned()).to_str().unwrap()) + .expect("Failed to read glob pattern") + .filter(|x| x.is_ok()) + { + self.keys.insert( + (*entry.unwrap().file_name().unwrap()) + .to_os_string() + .into_string() + .unwrap(), + "Blub".to_string(), + ); + } + } + + pub fn has_key(&self, ep: String, ulps: f64) -> bool { + self.keys.values().find(|v| (*v).eq(&ep)).is_some() + } +} + /// EKO output pub struct EKO { /// Working directory @@ -12,8 +43,12 @@ pub struct EKO { tar_path: Option, /// allow content modifications? read_only: bool, + /// final operators + operators: Inventory, } +const DIR_OPERATORS: &'static str = "operators"; + impl EKO { /// Check our working directory is safe. fn check(&self) -> Result<(), std::io::Error> { @@ -81,23 +116,51 @@ impl EKO { pub fn set_tar_path(&mut self, tar_path: PathBuf) { self.tar_path = Some(tar_path.to_owned()); } -} -/// Extract tar file from `src` to `dst`. -pub fn extract(src: PathBuf, dst: PathBuf, read_only: bool) -> EKO { - let mut ar = tar::Archive::new(File::open(src.to_owned()).unwrap()); - ar.unpack(dst.to_owned()).unwrap(); - EKO { - path: dst.to_owned(), - tar_path: Some(src.to_owned()), - read_only, + /// Open tar from `src` to `dst` for reading. + pub fn read(src: PathBuf, dst: PathBuf) -> Self { + Self::extract(src, dst, true) + } + + /// Open tar from `src` to `dst` for editing. + pub fn edit(src: PathBuf, dst: PathBuf) -> Self { + Self::extract(src, dst, false) + } + + /// Extract tar file from `src` to `dst`. + pub fn extract(src: PathBuf, dst: PathBuf, read_only: bool) -> Self { + let mut ar = tar::Archive::new(File::open(src.to_owned()).unwrap()); + ar.unpack(dst.to_owned()).unwrap(); + let mut obj = Self::load_opened(dst, read_only); + obj.set_tar_path(src); + obj + } + + /// Load an EKO from a directory `path` (instead of tar). + pub fn load_opened(path: PathBuf, read_only: bool) -> Self { + let mut operators = Inventory { + path: path.join(DIR_OPERATORS), + keys: HashMap::new(), + }; + operators.load_keys(); + Self { + path, + tar_path: None, + read_only, + operators, + } + } + + /// Check if the operator at the evolution point `ep` is available. + pub fn has_operator(&self, ep: String, ulps: f64) -> bool { + self.operators.has_key(ep, ulps) } } mod test { #[test] fn save_as_other() { - use super::extract; + use super::EKO; use std::fs::{remove_dir_all, remove_file}; use std::path::PathBuf; let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect(); @@ -110,7 +173,7 @@ mod test { let _ = remove_dir_all(dst.to_owned()); } // open - let mut eko = extract(src.to_owned(), dst.to_owned(), false); + let mut eko = EKO::edit(src.to_owned(), dst.to_owned()); let dst_exists = dst.try_exists().is_ok_and(|x| x); assert!(dst_exists); // set a different output @@ -131,4 +194,23 @@ mod test { let _ = remove_dir_all(dst.to_str().unwrap()); } } + + #[test] + fn read_keys() { + use super::EKO; + use std::fs::remove_dir_all; + use std::path::PathBuf; + let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect(); + let src = base.join("data").join("v0.15.tar"); + assert!(src.try_exists().is_ok_and(|x| x)); + let dst = base.join("target").join("v0.15"); + // get rid of previous runs if needed + let dst_exists = dst.try_exists().is_ok_and(|x| x); + if dst_exists { + let _ = remove_dir_all(dst.to_owned()); + } + // open + let eko = EKO::read(src.to_owned(), dst.to_owned()); + assert!(eko.has_operator("Blub".to_string(), 1e-7)); + } }