From 6d1700728ae87afffe84a062097c76a8159391f5 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 24 Mar 2021 09:56:25 +0800 Subject: [PATCH] Intern module registration strings. --- CHANGELOG.md | 1 + codegen/src/lib.rs | 89 +++++++++++++++++++---------------------- codegen/src/register.rs | 3 +- src/module/mod.rs | 68 +++++++++++++++++++------------ tests/plugins_unroll.rs | 2 +- 5 files changed, 87 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72117b4a..0efd5778 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Breaking changes * All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`. * `Array::reduce` and `Array::reduce_rev` now take a `Dynamic` as initial value instead of a function pointer. * `protected`, `super` are now reserved keywords. +* The `Module::set_fn_XXX` API now take `&str` as the function name instead of `Into`. Enhancements ------------ diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index a8bc11e8..c39e0860 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -212,10 +212,9 @@ pub fn export_module( #[proc_macro] pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream { let module_path = parse_macro_input!(module_path as syn::Path); - let tokens = quote::quote! { + proc_macro::TokenStream::from(quote::quote! { #module_path::rhai_module_generate() - }; - proc_macro::TokenStream::from(tokens) + }) } /// Macro to combine a _plugin module_ into an existing module. @@ -258,15 +257,12 @@ pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::Toke /// ``` #[proc_macro] pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - 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, true); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! { + #module_path::rhai_generate_into_module(#module_expr, true); + }), + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ (defined via [`#[export_fn]`][export_fn]) into an `Engine`. @@ -293,16 +289,15 @@ pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro /// ``` #[proc_macro] pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (engine_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((engine_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn); + }) + } + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ into a Rhai `Module`. @@ -332,19 +327,18 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS /// ``` #[proc_macro] pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (module_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, - Some(#gen_mod_path::token_param_names().as_ref()), - #gen_mod_path::token_input_types().as_ref(), - #gen_mod_path::token_callable()); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, + Some(#gen_mod_path::token_param_names().as_ref()), + #gen_mod_path::token_input_types().as_ref(), + #gen_mod_path::token_callable()); + }) + } + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ into a Rhai `Module` and expose it globally. @@ -374,17 +368,16 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream /// ``` #[proc_macro] pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (module_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, - Some(#gen_mod_path::token_param_names().as_ref()), - #gen_mod_path::token_input_types().as_ref(), - #gen_mod_path::token_callable()); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, + Some(#gen_mod_path::token_param_names().as_ref()), + #gen_mod_path::token_input_types().as_ref(), + #gen_mod_path::token_callable()); + }) + } + Err(e) => e.to_compile_error().into(), + } } diff --git a/codegen/src/register.rs b/codegen/src/register.rs index 8ea91fd3..5813e2c1 100644 --- a/codegen/src/register.rs +++ b/codegen/src/register.rs @@ -33,8 +33,7 @@ pub fn parse_register_macro( )); } let export_name = match &items[1] { - syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => - #lit_str.to_string()), + syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => #lit_str), expr => quote! { #expr }, }; let rust_mod_path = if let syn::Expr::Path(ref path) = &items[2] { diff --git a/src/module/mod.rs b/src/module/mod.rs index 13b8c405..abe0e51d 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -7,7 +7,7 @@ use crate::fn_register::RegisterNativeFunction; use crate::stdlib::{ any::TypeId, boxed::Box, - collections::BTreeMap, + collections::{BTreeMap, BTreeSet}, fmt, format, iter::empty, num::NonZeroUsize, @@ -54,7 +54,7 @@ pub struct FuncInfo { /// Function access mode. pub access: FnAccess, /// Function name. - pub name: String, + pub name: ImmutableString, /// Number of parameters. pub params: usize, /// Parameter types (if applicable). @@ -147,6 +147,8 @@ pub struct Module { indexed: bool, /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? contains_indexed_global_functions: bool, + /// Interned strings + interned_strings: BTreeSet, } impl Default for Module { @@ -163,6 +165,7 @@ impl Default for Module { all_type_iterators: Default::default(), indexed: false, contains_indexed_global_functions: false, + interned_strings: Default::default(), } } } @@ -172,11 +175,10 @@ impl fmt::Debug for Module { write!( f, "Module({}\n{}{}{})", - if let Some(ref id) = self.id { - format!("id: {:?},", id) - } else { - "".to_string() - }, + self.id + .as_ref() + .map(|id| format!("id: {:?},", id)) + .unwrap_or_default(), if !self.modules.is_empty() { format!( " modules: {}\n", @@ -359,6 +361,15 @@ impl Module { self.indexed } + /// Return an interned string. + fn get_interned_string(&mut self, s: &str) -> ImmutableString { + self.interned_strings.get(s).cloned().unwrap_or_else(|| { + let s: ImmutableString = s.into(); + self.interned_strings.insert(s.clone()); + s + }) + } + /// Generate signatures for all the non-private functions in the [`Module`]. #[inline(always)] pub fn gen_fn_signatures(&self) -> impl Iterator + '_ { @@ -466,12 +477,12 @@ impl Module { // None + function name + number of arguments. let num_params = fn_def.params.len(); let hash_script = crate::calc_fn_hash(empty(), &fn_def.name, num_params); - let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect(); + let mut param_names = fn_def.params.clone(); param_names.push("Dynamic".into()); self.functions.insert( hash_script, Box::new(FuncInfo { - name: fn_def.name.to_string(), + name: fn_def.name.clone(), namespace: FnNamespace::Internal, access: fn_def.access, params: num_params, @@ -612,8 +623,13 @@ impl Module { /// In other words, the number of entries should be one larger than the number of parameters. #[inline(always)] pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self { + let param_names = arg_names + .iter() + .map(|&name| self.get_interned_string(name)) + .collect(); + if let Some(f) = self.functions.get_mut(&hash_fn) { - f.param_names = arg_names.iter().map(|&n| n.into()).collect(); + f.param_names = param_names; } self } @@ -625,9 +641,9 @@ impl Module { pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { if let Some(f) = self.functions.get_mut(&hash_fn) { f.namespace = namespace; + self.indexed = false; + self.contains_indexed_global_functions = false; } - self.indexed = false; - self.contains_indexed_global_functions = false; self } @@ -641,14 +657,13 @@ impl Module { #[inline] pub fn set_fn( &mut self, - name: impl Into, + name: &str, namespace: FnNamespace, access: FnAccess, arg_names: Option<&[&str]>, arg_types: &[TypeId], func: CallableFunction, ) -> u64 { - let name = name.into(); let is_method = func.is_method(); let param_types = arg_types @@ -675,6 +690,13 @@ impl Module { let hash_fn = calc_native_fn_hash(empty(), &name, ¶m_types); + let name = self.get_interned_string(name); + let param_names = arg_names + .iter() + .flat_map(|p| p.iter()) + .map(|&name| self.get_interned_string(name)) + .collect(); + self.functions.insert( hash_fn, Box::new(FuncInfo { @@ -683,11 +705,7 @@ impl Module { access, params: param_types.len(), param_types, - param_names: if let Some(p) = arg_names { - p.iter().map(|&v| v.into()).collect() - } else { - Default::default() - }, + param_names, func: func.into(), }), ); @@ -767,7 +785,7 @@ impl Module { #[inline(always)] pub fn set_raw_fn( &mut self, - name: impl Into, + name: &str, namespace: FnNamespace, access: FnAccess, arg_types: &[TypeId], @@ -812,7 +830,7 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline(always)] - pub fn set_native_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_native_fn(&mut self, name: &str, func: F) -> u64 where T: Variant + Clone, F: RegisterNativeFunction>>, @@ -847,7 +865,7 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_getter_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_getter_fn(&mut self, name: &str, func: F) -> u64 where A: Variant + Clone, T: Variant + Clone, @@ -855,7 +873,7 @@ impl Module { F: Fn(&mut A) -> Result> + SendSync + 'static, { self.set_fn( - crate::engine::make_getter(&name.into()), + &crate::engine::make_getter(name), FnNamespace::Global, FnAccess::Public, None, @@ -888,7 +906,7 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_setter_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_setter_fn(&mut self, name: &str, func: F) -> u64 where A: Variant + Clone, B: Variant + Clone, @@ -896,7 +914,7 @@ impl Module { F: Fn(&mut A, B) -> Result<(), Box> + SendSync + 'static, { self.set_fn( - crate::engine::make_setter(&name.into()), + &crate::engine::make_setter(name), FnNamespace::Global, FnAccess::Public, None, diff --git a/tests/plugins_unroll.rs b/tests/plugins_unroll.rs index 9003e530..d94a7282 100644 --- a/tests/plugins_unroll.rs +++ b/tests/plugins_unroll.rs @@ -34,7 +34,7 @@ macro_rules! register_in_bulk { { let type_str = stringify!($type_names); set_exported_fn!($mod_name, - format!(concat!(stringify!($op_name), "_{}"), type_str), + &format!(concat!(stringify!($op_name), "_{}"), type_str), crate::$op_name::$type_names::op); } )*