diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index b9d8880d..3763b47e 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -152,6 +152,20 @@ pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::Toke proc_macro::TokenStream::from(tokens) } +#[proc_macro] +pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { + #[allow(unused_variables)] + let (module_expr, export_name, module_path) = match crate::register::parse_register_macro(args) + { + Ok(triple) => triple, + Err(e) => return e.to_compile_error().into(), + }; + let tokens = quote! { + #module_path::rhai_generate_into_module(#module_expr); + }; + proc_macro::TokenStream::from(tokens) +} + #[proc_macro] pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { let (engine_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args) diff --git a/codegen/src/module.rs b/codegen/src/module.rs index 1ebc25b8..d89bfbb9 100644 --- a/codegen/src/module.rs +++ b/codegen/src/module.rs @@ -191,6 +191,7 @@ impl Parse for Module { } } +#[allow(dead_code)] impl Module { pub fn attrs(&self) -> Option<&Vec> { self.mod_all.as_ref().map(|m| &m.attrs) diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index d318f351..911c7edc 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -17,6 +17,7 @@ pub(crate) fn generate_body( let mut set_fn_stmts: Vec = Vec::new(); let mut set_const_stmts: Vec = Vec::new(); let mut add_mod_blocks: Vec = Vec::new(); + let mut set_mod_blocks: Vec = Vec::new(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); for (const_name, const_expr) in consts { @@ -54,6 +55,14 @@ pub(crate) fn generate_body( }) .unwrap(), ); + set_mod_blocks.push( + syn::parse2::(quote! { + #(#cfg_attrs)* { + self::#module_name::rhai_generate_into_module(m); + } + }) + .unwrap(), + ); } // NB: these are token streams, because reparsing messes up "> >" vs ">>" @@ -137,6 +146,11 @@ pub(crate) fn generate_body( #(#add_mod_blocks)* m } + pub fn rhai_generate_into_module(m: &mut Module) { + #(#set_fn_stmts)* + #(#set_const_stmts)* + #(#set_mod_blocks)* + } } }) .unwrap(); diff --git a/doc/src/plugins/module.md b/doc/src/plugins/module.md index 40232140..24107fff 100644 --- a/doc/src/plugins/module.md +++ b/doc/src/plugins/module.md @@ -24,6 +24,9 @@ use rhai::plugins::*; // a "prelude" import for macros #[export_module] mod my_module { + // This constant will be registered as a the constant variable 'SOME_NUMBER'. + pub const SOME_NUMBER: i64 = 42; + // This function will be registered as 'greet'. pub fn greet(name: &str) -> String { format!("hello, {}!", name) diff --git a/doc/src/rust/packages/create.md b/doc/src/rust/packages/create.md index d212d38f..4f55cc13 100644 --- a/doc/src/rust/packages/create.md +++ b/doc/src/rust/packages/create.md @@ -63,8 +63,8 @@ By far the easiest way to create a custom module is to call `Module::merge_flatt In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented. -`rhai::plugins::exported_module!` generates a module from the [plugins][plugin module] definition, -and `Module::merge_flatten` consumes its, adding all its registered functions into the package itself. +`rhai::plugins::combine_with_exported_module!` adds all functions and constants from the +[plugins][plugin module] definition into the package itself. ```rust // Import necessary types and traits. @@ -94,7 +94,10 @@ def_package!(rhai:MyPackage:"My own personal super package", module, { BasicArrayPackage::init(module); BasicMapPackage::init(module); - // Merge the plugin module into the custom package. - module.merge_flatten(exported_module!(my_module)); + // Merge all registered functions and constants from the plugin module into the custom package. + // + // The text string name in the middle parameter can be anything and is reserved for future use; + // it is recommended to be an ID string that uniquely identifies the module. + combine_with_exported_module!(module, "my-functions", my_module)); }); ``` diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index d72e2e8b..f963e778 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -185,7 +185,7 @@ macro_rules! gen_signed_functions { macro_rules! reg_functions { ($mod_name:ident += $root:ident ; $($arg_type:ident),+ ) => { $( - $mod_name.combine_flatten(exported_module!($root::$arg_type::functions)); + combine_with_exported_module!($mod_name, "arithmetic", $root::$arg_type::functions); )* } } @@ -208,8 +208,8 @@ def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, { // Basic arithmetic for floating-point #[cfg(not(feature = "no_float"))] { - lib.combine_flatten(exported_module!(f32_functions)); - lib.combine_flatten(exported_module!(f64_functions)); + combine_with_exported_module!(lib, "f32", f32_functions); + combine_with_exported_module!(lib, "f64", f64_functions); } }); diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 767c4c5f..05599eac 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -58,7 +58,7 @@ macro_rules! reg_functions { } def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { - lib.combine_flatten(exported_module!(array_functions)); + combine_with_exported_module!(lib, "array", array_functions); reg_functions!(lib += basic; INT, bool, char, ImmutableString, FnPtr, Array, Unit); diff --git a/src/packages/eval.rs b/src/packages/eval.rs index acebf216..bb5716d8 100644 --- a/src/packages/eval.rs +++ b/src/packages/eval.rs @@ -5,7 +5,7 @@ use crate::plugin::*; use crate::result::EvalAltResult; def_package!(crate:EvalPackage:"Disable 'eval'.", lib, { - lib.combine_flatten(exported_module!(eval_override)); + combine_with_exported_module!(lib, "eval", eval_override); }); #[export_module] diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index 61d18371..5ffb6cb1 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -3,7 +3,7 @@ use crate::fn_native::FnPtr; use crate::plugin::*; def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, { - lib.combine_flatten(exported_module!(fn_ptr_functions)); + combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions); }); #[export_module] diff --git a/src/packages/logic.rs b/src/packages/logic.rs index 48e46047..554f30e3 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -45,7 +45,7 @@ macro_rules! gen_cmp_functions { macro_rules! reg_functions { ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( - $mod_name.combine_flatten(exported_module!($root::$arg_type::functions)); + combine_with_exported_module!($mod_name, "logic", $root::$arg_type::functions); )* } } diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index a5983268..fde57db7 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -9,7 +9,7 @@ use crate::plugin::*; use crate::stdlib::vec::Vec; def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, { - lib.combine_flatten(exported_module!(map_functions)); + combine_with_exported_module!(lib, "map", map_functions); }); #[export_module] diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index ddbb640c..2fd2a9c4 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -48,10 +48,10 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { #[cfg(not(feature = "no_float"))] { // Floating point functions - lib.combine_flatten(exported_module!(float_functions)); + combine_with_exported_module!(lib, "float", float_functions); // Trig functions - lib.combine_flatten(exported_module!(trig_functions)); + combine_with_exported_module!(lib, "trig", trig_functions); reg_functions!(lib += basic_to_float::to_float(INT)); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 5dfd4897..55fa4be0 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -57,7 +57,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str #[cfg(not(feature = "no_float"))] reg_functions!(lib += float; f32, f64); - lib.combine_flatten(exported_module!(string_functions)); + combine_with_exported_module!(lib, "string", string_functions); lib.set_raw_fn( "pad", diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index 80ba2637..caa5fc47 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -21,7 +21,7 @@ use instant::Instant; def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { // Register date/time functions - lib.combine_flatten(exported_module!(time_functions)); + combine_with_exported_module!(lib, "time", time_functions); }); #[export_module] diff --git a/tests/plugins.rs b/tests/plugins.rs index cac8718f..928f0381 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -1,5 +1,6 @@ #![cfg(not(any(feature = "no_index", feature = "no_module")))] +use rhai::module_resolvers::StaticModuleResolver; use rhai::plugin::*; use rhai::{Engine, EvalAltResult, INT}; @@ -10,6 +11,8 @@ mod test { pub mod special_array_package { use rhai::{Array, INT}; + pub const MYSTIC_NUMBER: INT = 42 as INT; + #[cfg(not(feature = "no_object"))] pub mod feature { use rhai::{Array, Dynamic, EvalAltResult}; @@ -66,7 +69,7 @@ fn test_plugins_package() -> Result<(), Box> { let mut engine = Engine::new(); let mut m = Module::new(); - m.combine_flatten(exported_module!(test::special_array_package)); + combine_with_exported_module!(&mut m, "test", test::special_array_package); engine.load_package(m); reg_functions!(engine += greet::single(INT, bool, char)); @@ -83,5 +86,14 @@ fn test_plugins_package() -> Result<(), Box> { "6 kitties" ); + let mut resolver = StaticModuleResolver::new(); + resolver.insert("test", exported_module!(test::special_array_package)); + + engine.set_module_resolver(Some(resolver)); + assert_eq!( + engine.eval::(r#"import "test" as test; test::MYSTIC_NUMBER"#)?, + 42 + ); + Ok(()) } diff --git a/xxx.rs b/xxx.rs new file mode 100644 index 00000000..e69de29b