Intern module registration strings.

This commit is contained in:
Stephen Chung 2021-03-24 09:56:25 +08:00
parent 0d7f2c16cc
commit 6d1700728a
5 changed files with 87 additions and 76 deletions

View File

@ -26,6 +26,7 @@ Breaking changes
* All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`. * 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. * `Array::reduce` and `Array::reduce_rev` now take a `Dynamic` as initial value instead of a function pointer.
* `protected`, `super` are now reserved keywords. * `protected`, `super` are now reserved keywords.
* The `Module::set_fn_XXX` API now take `&str` as the function name instead of `Into<String>`.
Enhancements Enhancements
------------ ------------

View File

@ -212,10 +212,9 @@ pub fn export_module(
#[proc_macro] #[proc_macro]
pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream {
let module_path = parse_macro_input!(module_path as syn::Path); 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() #module_path::rhai_module_generate()
}; })
proc_macro::TokenStream::from(tokens)
} }
/// Macro to combine a _plugin module_ into an existing module. /// 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] #[proc_macro]
pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { 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) match crate::register::parse_register_macro(args) {
{ Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! {
Ok(triple) => triple, #module_path::rhai_generate_into_module(#module_expr, true);
Err(e) => return e.to_compile_error().into(), }),
}; Err(e) => e.to_compile_error().into(),
let tokens = quote! { }
#module_path::rhai_generate_into_module(#module_expr, true);
};
proc_macro::TokenStream::from(tokens)
} }
/// Macro to register a _plugin function_ (defined via [`#[export_fn]`][export_fn]) into an `Engine`. /// 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] #[proc_macro]
pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { 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) {
match crate::register::parse_register_macro(args) { Ok((engine_expr, export_name, rust_mod_path)) => {
Ok(triple) => triple, let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
Err(e) => return e.to_compile_error().into(), proc_macro::TokenStream::from(quote! {
}; #engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn);
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); Err(e) => e.to_compile_error().into(),
}; }
proc_macro::TokenStream::from(tokens)
} }
/// Macro to register a _plugin function_ into a Rhai `Module`. /// 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] #[proc_macro]
pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { 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) {
match crate::register::parse_register_macro(args) { Ok((module_expr, export_name, rust_mod_path)) => {
Ok(triple) => triple, let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
Err(e) => return e.to_compile_error().into(), proc_macro::TokenStream::from(quote! {
}; #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); Some(#gen_mod_path::token_param_names().as_ref()),
let tokens = quote! { #gen_mod_path::token_input_types().as_ref(),
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, #gen_mod_path::token_callable());
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(),
}; }
proc_macro::TokenStream::from(tokens)
} }
/// Macro to register a _plugin function_ into a Rhai `Module` and expose it globally. /// 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] #[proc_macro]
pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { 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) {
match crate::register::parse_register_macro(args) { Ok((module_expr, export_name, rust_mod_path)) => {
Ok(triple) => triple, let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
Err(e) => return e.to_compile_error().into(), proc_macro::TokenStream::from(quote! {
}; #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); Some(#gen_mod_path::token_param_names().as_ref()),
let tokens = quote! { #gen_mod_path::token_input_types().as_ref(),
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, #gen_mod_path::token_callable());
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(),
}; }
proc_macro::TokenStream::from(tokens)
} }

View File

@ -33,8 +33,7 @@ pub fn parse_register_macro(
)); ));
} }
let export_name = match &items[1] { let export_name = match &items[1] {
syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => #lit_str),
#lit_str.to_string()),
expr => quote! { #expr }, expr => quote! { #expr },
}; };
let rust_mod_path = if let syn::Expr::Path(ref path) = &items[2] { let rust_mod_path = if let syn::Expr::Path(ref path) = &items[2] {

View File

@ -7,7 +7,7 @@ use crate::fn_register::RegisterNativeFunction;
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, any::TypeId,
boxed::Box, boxed::Box,
collections::BTreeMap, collections::{BTreeMap, BTreeSet},
fmt, format, fmt, format,
iter::empty, iter::empty,
num::NonZeroUsize, num::NonZeroUsize,
@ -54,7 +54,7 @@ pub struct FuncInfo {
/// Function access mode. /// Function access mode.
pub access: FnAccess, pub access: FnAccess,
/// Function name. /// Function name.
pub name: String, pub name: ImmutableString,
/// Number of parameters. /// Number of parameters.
pub params: usize, pub params: usize,
/// Parameter types (if applicable). /// Parameter types (if applicable).
@ -147,6 +147,8 @@ pub struct Module {
indexed: bool, indexed: bool,
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
contains_indexed_global_functions: bool, contains_indexed_global_functions: bool,
/// Interned strings
interned_strings: BTreeSet<ImmutableString>,
} }
impl Default for Module { impl Default for Module {
@ -163,6 +165,7 @@ impl Default for Module {
all_type_iterators: Default::default(), all_type_iterators: Default::default(),
indexed: false, indexed: false,
contains_indexed_global_functions: false, contains_indexed_global_functions: false,
interned_strings: Default::default(),
} }
} }
} }
@ -172,11 +175,10 @@ impl fmt::Debug for Module {
write!( write!(
f, f,
"Module({}\n{}{}{})", "Module({}\n{}{}{})",
if let Some(ref id) = self.id { self.id
format!("id: {:?},", id) .as_ref()
} else { .map(|id| format!("id: {:?},", id))
"".to_string() .unwrap_or_default(),
},
if !self.modules.is_empty() { if !self.modules.is_empty() {
format!( format!(
" modules: {}\n", " modules: {}\n",
@ -359,6 +361,15 @@ impl Module {
self.indexed 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`]. /// Generate signatures for all the non-private functions in the [`Module`].
#[inline(always)] #[inline(always)]
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ { pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
@ -466,12 +477,12 @@ impl Module {
// None + function name + number of arguments. // None + function name + number of arguments.
let num_params = fn_def.params.len(); let num_params = fn_def.params.len();
let hash_script = crate::calc_fn_hash(empty(), &fn_def.name, num_params); 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()); param_names.push("Dynamic".into());
self.functions.insert( self.functions.insert(
hash_script, hash_script,
Box::new(FuncInfo { Box::new(FuncInfo {
name: fn_def.name.to_string(), name: fn_def.name.clone(),
namespace: FnNamespace::Internal, namespace: FnNamespace::Internal,
access: fn_def.access, access: fn_def.access,
params: num_params, 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. /// In other words, the number of entries should be one larger than the number of parameters.
#[inline(always)] #[inline(always)]
pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self { 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) { 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 self
} }
@ -625,9 +641,9 @@ impl Module {
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
if let Some(f) = self.functions.get_mut(&hash_fn) { if let Some(f) = self.functions.get_mut(&hash_fn) {
f.namespace = namespace; f.namespace = namespace;
self.indexed = false;
self.contains_indexed_global_functions = false;
} }
self.indexed = false;
self.contains_indexed_global_functions = false;
self self
} }
@ -641,14 +657,13 @@ impl Module {
#[inline] #[inline]
pub fn set_fn( pub fn set_fn(
&mut self, &mut self,
name: impl Into<String>, name: &str,
namespace: FnNamespace, namespace: FnNamespace,
access: FnAccess, access: FnAccess,
arg_names: Option<&[&str]>, arg_names: Option<&[&str]>,
arg_types: &[TypeId], arg_types: &[TypeId],
func: CallableFunction, func: CallableFunction,
) -> u64 { ) -> u64 {
let name = name.into();
let is_method = func.is_method(); let is_method = func.is_method();
let param_types = arg_types let param_types = arg_types
@ -675,6 +690,13 @@ impl Module {
let hash_fn = calc_native_fn_hash(empty(), &name, &param_types); let hash_fn = calc_native_fn_hash(empty(), &name, &param_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( self.functions.insert(
hash_fn, hash_fn,
Box::new(FuncInfo { Box::new(FuncInfo {
@ -683,11 +705,7 @@ impl Module {
access, access,
params: param_types.len(), params: param_types.len(),
param_types, param_types,
param_names: if let Some(p) = arg_names { param_names,
p.iter().map(|&v| v.into()).collect()
} else {
Default::default()
},
func: func.into(), func: func.into(),
}), }),
); );
@ -767,7 +785,7 @@ impl Module {
#[inline(always)] #[inline(always)]
pub fn set_raw_fn<T: Variant + Clone>( pub fn set_raw_fn<T: Variant + Clone>(
&mut self, &mut self,
name: impl Into<String>, name: &str,
namespace: FnNamespace, namespace: FnNamespace,
access: FnAccess, access: FnAccess,
arg_types: &[TypeId], arg_types: &[TypeId],
@ -812,7 +830,7 @@ impl Module {
/// assert!(module.contains_fn(hash)); /// assert!(module.contains_fn(hash));
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn set_native_fn<ARGS, T, F>(&mut self, name: impl Into<String>, func: F) -> u64 pub fn set_native_fn<ARGS, T, F>(&mut self, name: &str, func: F) -> u64
where where
T: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>, F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
@ -847,7 +865,7 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_getter_fn<ARGS, A, T, F>(&mut self, name: impl Into<String>, func: F) -> u64 pub fn set_getter_fn<ARGS, A, T, F>(&mut self, name: &str, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
T: Variant + Clone, T: Variant + Clone,
@ -855,7 +873,7 @@ impl Module {
F: Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static, F: Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
{ {
self.set_fn( self.set_fn(
crate::engine::make_getter(&name.into()), &crate::engine::make_getter(name),
FnNamespace::Global, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
None, None,
@ -888,7 +906,7 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_setter_fn<ARGS, A, B, F>(&mut self, name: impl Into<String>, func: F) -> u64 pub fn set_setter_fn<ARGS, A, B, F>(&mut self, name: &str, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
B: Variant + Clone, B: Variant + Clone,
@ -896,7 +914,7 @@ impl Module {
F: Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static, F: Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
{ {
self.set_fn( self.set_fn(
crate::engine::make_setter(&name.into()), &crate::engine::make_setter(name),
FnNamespace::Global, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
None, None,

View File

@ -34,7 +34,7 @@ macro_rules! register_in_bulk {
{ {
let type_str = stringify!($type_names); let type_str = stringify!($type_names);
set_exported_fn!($mod_name, 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); crate::$op_name::$type_names::op);
} }
)* )*