diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 800aee6..215fbb1 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -45,7 +45,7 @@ jobs: - name: build env: RUSTFLAGS: -Cinstrument-coverage - run: cargo build --verbose + run: cargo build --all-features --verbose - name: test env: diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 43e27cc..d3eb0b9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,7 +46,7 @@ jobs: cargo fmt -- --check - name: Clippy - run: cargo clippy --all-targets -- -D warnings + run: cargo clippy --all-features --all-targets -- -D warnings - name: Build run: cargo build --all-features --verbose diff --git a/config/Cargo.toml b/config/Cargo.toml index 80af4f1..34e7fa3 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -10,8 +10,11 @@ readme = "README.md" authors = ["Brady Fomegne "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["rhai"] +rhai = ["dep:rhai"] [dependencies] -rhai = "1.16.2" +rhai = { version = "1.16.2", optional = true } serde = { version = "1.0.188", features = ["derive"] } toml = "0.8.2" diff --git a/config/src/lib.rs b/config/src/lib.rs index 0edb20d..d54040c 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -3,6 +3,7 @@ #![deny(missing_docs)] +#[cfg(feature = "rhai")] use rhai::{Engine, AST}; use serde::Deserialize; use std::result::Result; @@ -15,6 +16,7 @@ pub struct Config { /// The core config. pub core: Option, data: Option>, + #[cfg(feature = "rhai")] translators: Option>, translation: Option>, } @@ -113,26 +115,29 @@ impl Config { config.data = Some(data); // Translators - let mut translators = HashMap::new(); - - config.translators.unwrap_or_default().iter().try_for_each( - |(key, value)| -> Result<(), Box> { - match value { - Data::File(DataFile { path }) => { - let filepath = config_path.join(path); - let conf = Config::from_file(&filepath)?; - translators.extend(conf.translators.unwrap_or_default()); - } - Data::Simple(value) => { - let filepath = config_path.join(value.clone()).to_str().unwrap().to_string(); - translators.insert(key.to_owned(), Data::Simple(filepath)); - } - _ => Err(format!("Invalid script file `{filepath:?}`.\nCaused by:\n\t{value:?} not allowed in the translator table."))?, - }; - Ok(()) - }, - )?; - config.translators = Some(translators); + #[cfg(feature = "rhai")] + { + let mut translators = HashMap::new(); + + config.translators.unwrap_or_default().iter().try_for_each( + |(key, value)| -> Result<(), Box> { + match value { + Data::File(DataFile { path }) => { + let filepath = config_path.join(path); + let conf = Config::from_file(&filepath)?; + translators.extend(conf.translators.unwrap_or_default()); + } + Data::Simple(value) => { + let filepath = config_path.join(value.clone()).to_str().unwrap().to_string(); + translators.insert(key.to_owned(), Data::Simple(filepath)); + } + _ => Err(format!("Invalid script file `{filepath:?}`.\nCaused by:\n\t{value:?} not allowed in the translator table."))?, + }; + Ok(()) + }, + )?; + config.translators = Some(translators); + } // Translation let mut translation = HashMap::new(); @@ -187,6 +192,7 @@ impl Config { } /// Extract the translators from the configuration. + #[cfg(feature = "rhai")] pub fn extract_translators(&self) -> Result, Box> { let empty = HashMap::default(); let mut engine = Engine::new(); @@ -282,14 +288,15 @@ mod tests { // invalid data let conf = Config::from_file(Path::new("./data/invalid_data.toml")); assert!(conf.is_err()); + } + #[cfg(feature = "rhai")] + #[test] + fn from_file_with_translators() { // invalid translator let conf = Config::from_file(Path::new("./data/invalid_translator.toml")); assert!(conf.is_err()); - } - #[test] - fn from_file_with_translators() { let conf = Config::from_file(Path::new("./data/config_sample.toml")).unwrap(); let translators = conf.extract_translators().unwrap(); assert_eq!(translators.keys().len(), 2); diff --git a/engine/translator/Cargo.toml b/engine/translator/Cargo.toml index b1c3dac..3cda528 100644 --- a/engine/translator/Cargo.toml +++ b/engine/translator/Cargo.toml @@ -11,5 +11,9 @@ authors = ["Brady Fomegne "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["rhai"] +rhai = ["dep:rhai"] + [dependencies] -rhai = "1.16.2" +rhai = { version = "1.16.2", optional = true } diff --git a/engine/translator/src/lib.rs b/engine/translator/src/lib.rs index 3503944..04f56f9 100644 --- a/engine/translator/src/lib.rs +++ b/engine/translator/src/lib.rs @@ -2,29 +2,34 @@ //! //! Example //! ```rust -//! use clafrica_translator::{Engine, Translator}; +//! #[cfg(feature = "rhai")] +//! use clafrica_translator::Engine; +//! use clafrica_translator::Translator; //! use std::collections::HashMap; //! -//! // Translation via scripting -//! let engine = Engine::new(); -//! let hi = engine.compile(r#" -//! fn translate(input) { -//! if input == "hi" { -//! ["hi", "", "hello", true] -//! } -//! } -//! "#).unwrap(); -//! let mut translators = HashMap::new(); -//! translators.insert("hi".to_string(), hi); -//! //! // Translation via dictionary //! let mut dictionary = HashMap::new(); //! dictionary.insert("halo".to_string(), ["hello".to_string()].to_vec()); //! dictionary.insert("nihao".to_string(), ["hello".to_string()].to_vec()); //! //! // We build the translator. -//! let translator = Translator::new(dictionary, translators, true); +//! let mut translator = Translator::new(dictionary, true); +//! +//! // Translation via scripting +//! #[cfg(feature = "rhai")] +//! { +//! let engine = Engine::new(); +//! let hi = engine.compile(r#" +//! fn translate(input) { +//! if input == "hi" { +//! ["hi", "", "hello", true] +//! } +//! } +//! "#).unwrap(); +//! translator.register("hi".to_string(), hi); +//! } //! +//! #[cfg(feature = "rhai")] //! assert_eq!( //! translator.translate("hi"), //! vec![( @@ -39,58 +44,72 @@ #![deny(missing_docs)] +#[cfg(feature = "rhai")] pub use rhai::Engine; +#[cfg(feature = "rhai")] use rhai::{Array, Scope, AST}; use std::collections::HashMap; /// Core structure of the translator. pub struct Translator { dictionary: HashMap>, + #[cfg(feature = "rhai")] translators: HashMap, auto_commit: bool, } impl Translator { /// Initiate a new translator. - pub fn new( - dictionary: HashMap>, - translators: HashMap, - auto_commit: bool, - ) -> Self { + pub fn new(dictionary: HashMap>, auto_commit: bool) -> Self { Self { dictionary, - translators, auto_commit, + #[cfg(feature = "rhai")] + translators: HashMap::default(), } } + #[cfg(feature = "rhai")] + /// Register a translator + pub fn register(&mut self, name: String, ast: AST) { + self.translators.insert(name, ast); + } + + #[cfg(feature = "rhai")] + /// Unregister a translator + pub fn unregister(&mut self, name: &str) { + self.translators.remove(name); + } + /// Generate a list of predicates based on the input. pub fn translate(&self, input: &str) -> Vec<(String, String, Vec, bool)> { + #[cfg(feature = "rhai")] let mut scope = Scope::new(); + #[cfg(feature = "rhai")] let engine = Engine::new(); - self.dictionary - .iter() - .filter_map(|(key, value)| { - if key == input { - Some(( - key.to_owned(), - "".to_owned(), - value.to_owned(), - self.auto_commit, - )) - } else if input.len() > 1 && key.starts_with(input) { - Some(( - key.to_owned(), - key.chars().skip(input.len()).collect(), - value.to_owned(), - false, - )) - } else { - None - } - }) - .chain(self.translators.iter().filter_map(|(_name, translator)| { + let predicates = self.dictionary.iter().filter_map(|(key, value)| { + if key == input { + Some(( + key.to_owned(), + "".to_owned(), + value.to_owned(), + self.auto_commit, + )) + } else if input.len() > 1 && key.starts_with(input) { + Some(( + key.to_owned(), + key.chars().skip(input.len()).collect(), + value.to_owned(), + false, + )) + } else { + None + } + }); + #[cfg(feature = "rhai")] + let predicates = + predicates.chain(self.translators.iter().filter_map(|(_name, translator)| { let data = engine .call_fn::(&mut scope, translator, "translate", (input.to_owned(),)) .unwrap_or_default(); @@ -109,8 +128,8 @@ impl Translator { (code, remaining_code, texts, translated) }) - })) - .collect() + })); + predicates.collect() } } @@ -118,32 +137,44 @@ impl Translator { mod tests { #[test] fn test_translate() { - use crate::{Engine, Translator}; + #[cfg(feature = "rhai")] + use crate::Engine; + use crate::Translator; use std::collections::HashMap; - let engine = Engine::new(); - let ast1 = engine.compile("fn translate(input) {}").unwrap(); - let ast2 = engine - .compile( - r#" - fn translate(input) { - if input == "hi" { - ["hi", "", "hello", true] - } - } - "#, - ) - .unwrap(); - let mut translators = HashMap::new(); - translators.insert("none".to_string(), ast1); - translators.insert("some".to_string(), ast2); - + // We build the translation let mut dictionary = HashMap::new(); dictionary.insert("halo".to_string(), ["hello".to_string()].to_vec()); - let translator = Translator::new(dictionary, translators, true); + // We config the translator + #[cfg(not(feature = "rhai"))] + let translator = Translator::new(dictionary, true); + #[cfg(feature = "rhai")] + let mut translator = Translator::new(dictionary, true); + + // + #[cfg(feature = "rhai")] + { + let engine = Engine::new(); + let ast1 = engine.compile("fn translate(input) {}").unwrap(); + let ast2 = engine + .compile( + r#" + fn translate(input) { + if input == "hi" { + ["hi", "", "hello", true] + } + } + "#, + ) + .unwrap(); + translator.register("none".to_string(), ast1); + translator.unregister("none"); + translator.register("some".to_string(), ast2); + } assert_eq!(translator.translate("h"), vec![]); + #[cfg(feature = "rhai")] assert_eq!( translator.translate("hi"), vec![( diff --git a/service/Cargo.toml b/service/Cargo.toml index 3f52f36..c151c43 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -16,12 +16,16 @@ doc = false name = "clafrica" path = "./src/main.rs" +[features] +default = ["rhai"] +rhai = ["clafrica-config/rhai", "clafrica-translator/rhai"] + [dependencies] clap = { version = "4.4.6", features = ["derive"] } enigo = "0.1.3" -clafrica-config = { version = "0.4.1", path = "../config" } +clafrica-config = { version = "0.4.1", path = "../config", default-features = false } clafrica-preprocessor = { version = "0.5.0", path = "../engine/preprocessor" } -clafrica-translator = { version = "0.0.1", path = "../engine/translator" } +clafrica-translator = { version = "0.0.1", path = "../engine/translator", default-features = false } rdev = "0.5.3" [dev-dependencies] diff --git a/service/src/lib.rs b/service/src/lib.rs index b0d4650..2a23651 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -31,11 +31,16 @@ pub fn run(config: Config, mut frontend: impl Frontend) -> Result<(), Box