Merge pull request #298 from schungx/master

Add get_fn_metadata_list.
This commit is contained in:
Stephen Chung 2020-11-23 22:05:05 +08:00 committed by GitHub
commit 9dcf47a5f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 630 additions and 99 deletions

View File

@ -22,7 +22,7 @@ Breaking changes
----------------
* `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`.
* `Module::set_fn` takes a further parameter with a list of parameter names and types, if any.
* `Module::set_fn` takes a further parameter with a list of parameter names/types plus the function return type, if any.
* `Module::get_sub_module_mut` is removed.
* `begin`, `end`, `unless` are now reserved keywords.
* `EvalPackage` is removed in favor of `Engine::disable_symbol`.
@ -37,8 +37,9 @@ New features
* New `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace.
* `Module::set_fn_XXX_mut` can expose a module function to the global namespace. This is convenient when registering an API for a custom type.
* `Module::set_getter_fn`, `Module::set_setter_fn`, `Module::set_indexer_get_fn`, `Module::set_indexer_set_fn` all expose the function to the global namespace by default. This is convenient when registering an API for a custom type.
* New `Module::update_fn_param_names` to update a module function's parameter names and types.
* New `Module::update_fn_metadata` to update a module function's parameter names and types.
* New `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type.
* New `get_fn_metadata_list` to get the metadata of all script-defined functions in scope.
Enhancements
------------

View File

@ -84,7 +84,15 @@ pub(crate) fn flatten_type_groups(ty: &syn::Type) -> &syn::Type {
}
pub(crate) fn print_type(ty: &syn::Type) -> String {
ty.to_token_stream().to_string().replace("& ", "&")
ty.to_token_stream()
.to_string()
.replace(" , ", ", ")
.replace("& ", "&")
.replace(" :: ", "::")
.replace(" ( ", "(")
.replace(" ) ", ")")
.replace(" < ", "<")
.replace(" > ", ">")
}
#[derive(Debug, Default)]
@ -582,6 +590,7 @@ impl ExportedFn {
let callable_block = self.generate_callable("Token");
let input_names_block = self.generate_input_names("Token");
let input_types_block = self.generate_input_types("Token");
let return_type_block = self.generate_return_type("Token");
let dyn_result_fn_block = self.generate_dynamic_fn();
quote! {
#[allow(unused)]
@ -592,6 +601,7 @@ impl ExportedFn {
#callable_block
#input_names_block
#input_types_block
#return_type_block
#dyn_result_fn_block
}
}
@ -687,6 +697,19 @@ impl ExportedFn {
}
}
pub fn generate_return_type(&self, on_type_name: &str) -> proc_macro2::TokenStream {
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
let return_type_fn_name: syn::Ident = syn::Ident::new(
format!("{}_return_type", on_type_name.to_lowercase()).as_str(),
self.name().span(),
);
quote! {
pub fn #return_type_fn_name() -> &'static str {
#token_name().return_type()
}
}
}
pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream {
let sig_name = self.name().clone();
let name = self.params.name.as_ref().map_or_else(
@ -701,6 +724,12 @@ impl ExportedFn {
let mut unpack_exprs: Vec<syn::Expr> = Vec::new();
let mut input_type_names: Vec<String> = Vec::new();
let mut input_type_exprs: Vec<syn::Expr> = Vec::new();
let return_type = self
.return_type()
.map(print_type)
.unwrap_or_else(|| "()".to_string());
let skip_first_arg;
if self.pass_context {
@ -867,6 +896,9 @@ impl ExportedFn {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![#(#input_type_exprs),*].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
#return_type
}
}
}
}

View File

@ -136,6 +136,11 @@ pub(crate) fn generate_body(
})
.collect();
let return_type = function
.return_type()
.map(print_type)
.unwrap_or_else(|| "()".to_string());
if let Some(ns) = function.params().namespace {
namespace = ns;
}
@ -151,7 +156,7 @@ pub(crate) fn generate_body(
set_fn_stmts.push(
syn::parse2::<syn::Stmt>(quote! {
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
Some(&[#(#fn_input_names),*]), &[#(#fn_input_types),*],
Some(&[#(#fn_input_names,)* #return_type]), &[#(#fn_input_types),*],
#fn_token_name().into());
})
.unwrap(),
@ -166,6 +171,7 @@ pub(crate) fn generate_body(
gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_input_names(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_return_type(&fn_token_name.to_string()));
}
let mut generate_fncall = syn::parse2::<syn::ItemMod>(quote! {

View File

@ -292,6 +292,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -302,6 +305,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(do_nothing()))
}
@ -340,6 +346,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -350,6 +359,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn(x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(do_something(x)))
}
@ -388,6 +400,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -398,6 +413,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(do_something(context, x)))
}
@ -438,6 +456,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"rhai::Dynamic"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -448,6 +469,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
Ok(return_dynamic())
}
@ -482,7 +506,10 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
}
fn return_type(&self) -> &'static str {
"()"
}
}
};
let item_fn = syn::parse2::<ExportedFn>(input_tokens).unwrap();
@ -519,6 +546,9 @@ mod generate_tests {
new_vec![TypeId::of::<usize>(),
TypeId::of::<usize>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"usize"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -529,6 +559,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn(x: usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(add_together(x, y)))
}
@ -569,6 +602,9 @@ mod generate_tests {
new_vec![TypeId::of::<usize>(),
TypeId::of::<usize>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -579,6 +615,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(increment(x, y)))
}
@ -618,6 +657,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn token_callable() -> CallableFunction {
Token().into()
@ -628,6 +670,9 @@ mod generate_tests {
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
pub fn token_return_type() -> &'static str {
Token().return_type()
}
pub fn dynamic_result_fn(message: &str) -> Result<Dynamic, Box<EvalAltResult> > {
Ok(Dynamic::from(special_print(message)))
}

View File

@ -297,7 +297,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&["INT"]), &[],
get_mystic_number_token().into());
if flatten {} else {}
}
@ -321,6 +321,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into()
@ -331,6 +334,9 @@ mod generate_tests {
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types()
}
pub fn get_mystic_number_token_return_type() -> &'static str {
get_mystic_number_token().return_type()
}
}
};
@ -365,7 +371,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT", "INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
if flatten {} else {}
}
@ -390,6 +396,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
@ -400,6 +409,9 @@ mod generate_tests {
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
pub fn add_one_to_token_return_type() -> &'static str {
add_one_to_token().return_type()
}
}
};
@ -433,7 +445,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
if flatten {} else {}
}
@ -458,6 +470,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
@ -468,6 +483,9 @@ mod generate_tests {
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
pub fn add_one_to_token_return_type() -> &'static str {
add_one_to_token().return_type()
}
}
};
@ -512,9 +530,9 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_n_to_token().into());
if flatten {} else {}
@ -540,6 +558,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
@ -550,6 +571,9 @@ mod generate_tests {
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
pub fn add_one_to_token_return_type() -> &'static str {
add_one_to_token().return_type()
}
#[allow(non_camel_case_types)]
struct add_n_to_token();
@ -574,6 +598,9 @@ mod generate_tests {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_n_to_token_callable() -> CallableFunction {
add_n_to_token().into()
@ -584,6 +611,9 @@ mod generate_tests {
pub fn add_n_to_token_input_types() -> Box<[TypeId]> {
add_n_to_token().input_types()
}
pub fn add_n_to_token_return_type() -> &'static str {
add_n_to_token().return_type()
}
}
};
@ -617,7 +647,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
if flatten {} else {}
@ -645,6 +675,9 @@ mod generate_tests {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into()
@ -655,6 +688,9 @@ mod generate_tests {
pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types()
}
pub fn add_together_token_return_type() -> &'static str {
add_together_token().return_type()
}
}
};
@ -689,13 +725,13 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
if flatten {} else {}
@ -723,6 +759,9 @@ mod generate_tests {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into()
@ -733,6 +772,9 @@ mod generate_tests {
pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types()
}
pub fn add_together_token_return_type() -> &'static str {
add_together_token().return_type()
}
}
};
@ -948,7 +990,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&["INT"]), &[],
get_mystic_number_token().into());
if flatten {} else {}
}
@ -972,6 +1014,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"INT"
}
}
pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into()
@ -982,6 +1027,9 @@ mod generate_tests {
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types()
}
pub fn get_mystic_number_token_return_type() -> &'static str {
get_mystic_number_token().return_type()
}
}
};
@ -1047,7 +1095,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &str"]), &[core::any::TypeId::of::<ImmutableString>()],
Some(&["x: &str", "()"]), &[core::any::TypeId::of::<ImmutableString>()],
print_out_to_token().into());
if flatten {} else {}
}
@ -1072,6 +1120,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into()
@ -1082,6 +1133,9 @@ mod generate_tests {
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types()
}
pub fn print_out_to_token_return_type() -> &'static str {
print_out_to_token().return_type()
}
}
};
@ -1116,7 +1170,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
Some(&["x: String"]), &[core::any::TypeId::of::<ImmutableString>()],
Some(&["x: String", "()"]), &[core::any::TypeId::of::<ImmutableString>()],
print_out_to_token().into());
if flatten {} else {}
}
@ -1141,6 +1195,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into()
@ -1151,6 +1208,9 @@ mod generate_tests {
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types()
}
pub fn print_out_to_token_return_type() -> &'static str {
print_out_to_token().return_type()
}
}
};
@ -1185,7 +1245,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT", "()"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1210,6 +1270,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
@ -1220,6 +1283,9 @@ mod generate_tests {
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
pub fn increment_token_return_type() -> &'static str {
increment_token().return_type()
}
}
};
@ -1257,7 +1323,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT", "()"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1282,6 +1348,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
@ -1292,6 +1361,9 @@ mod generate_tests {
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
pub fn increment_token_return_type() -> &'static str {
increment_token().return_type()
}
}
#[allow(unused_imports)]
use super::*;
@ -1350,7 +1422,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT", "()"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1375,6 +1447,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
@ -1385,6 +1460,9 @@ mod generate_tests {
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
pub fn increment_token_return_type() -> &'static str {
increment_token().return_type()
}
}
#[allow(unused_imports)]
use super::*;
@ -1441,7 +1519,8 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]),
&[core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1466,6 +1545,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"u64"
}
}
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
@ -1476,6 +1558,9 @@ mod generate_tests {
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
pub fn int_foo_token_return_type() -> &'static str {
int_foo_token().return_type()
}
}
};
@ -1510,9 +1595,9 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::<u64>()],
int_foo_token().into());
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), &[core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1537,6 +1622,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"u64"
}
}
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
@ -1547,6 +1635,9 @@ mod generate_tests {
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
pub fn int_foo_token_return_type() -> &'static str {
int_foo_token().return_type()
}
}
};
@ -1581,7 +1672,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
@ -1608,6 +1699,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
@ -1618,6 +1712,9 @@ mod generate_tests {
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
pub fn int_foo_token_return_type() -> &'static str {
int_foo_token().return_type()
}
}
};
@ -1652,10 +1749,10 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
@ -1682,6 +1779,9 @@ mod generate_tests {
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
@ -1692,6 +1792,9 @@ mod generate_tests {
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
pub fn int_foo_token_return_type() -> &'static str {
int_foo_token().return_type()
}
}
};
@ -1727,7 +1830,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
@ -1756,6 +1859,9 @@ mod generate_tests {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"FLOAT"
}
}
pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into()
@ -1766,6 +1872,9 @@ mod generate_tests {
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
pub fn get_by_index_token_return_type() -> &'static str {
get_by_index_token().return_type()
}
}
};
@ -1801,12 +1910,12 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
@ -1835,6 +1944,9 @@ mod generate_tests {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"FLOAT"
}
}
pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into()
@ -1845,6 +1957,9 @@ mod generate_tests {
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
pub fn get_by_index_token_return_type() -> &'static str {
get_by_index_token().return_type()
}
}
};
@ -1880,7 +1995,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
@ -1912,6 +2027,9 @@ mod generate_tests {
TypeId::of::<u64>(),
TypeId::of::<FLOAT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into()
@ -1922,6 +2040,9 @@ mod generate_tests {
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}
pub fn set_by_index_token_return_type() -> &'static str {
set_by_index_token().return_type()
}
}
};
@ -1957,13 +2078,13 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
set_by_index_token().into());
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
@ -1995,6 +2116,9 @@ mod generate_tests {
TypeId::of::<u64>(),
TypeId::of::<FLOAT>()].into_boxed_slice()
}
fn return_type(&self) -> &'static str {
"()"
}
}
pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into()
@ -2005,6 +2129,9 @@ mod generate_tests {
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}
pub fn set_by_index_token_return_type() -> &'static str {
set_by_index_token().return_type()
}
}
};

View File

@ -135,6 +135,7 @@ The Rhai Scripting Language
2. [Custom Operators](engine/custom-op.md)
3. [Extending with Custom Syntax](engine/custom-syntax.md)
5. [Multiple Instantiation](patterns/multiple.md)
6. [Get Function Signatures](engine/get_fn_sig.md)
10. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.md)
2. [Operators and Symbols](appendix/operators.md)

View File

@ -0,0 +1,87 @@
Get Function Signatures
=======================
{{#include ../links.md}}
`Engine::gen_fn_signatures`
--------------------------
As part of a _reflections_ API, `Engine::gen_fn_signatures` returns a list of function signatures
(`Vec<String>`), each corresponding to a particular function available to that [`Engine`] instance.
Functions from the following sources are included, in order:
1) Functions registered into the global namespace via the `Engine::register_XXX` API,
2) Functions in global sub-modules registered via [`Engine::register_module`]({{rootUrl}}/rust/modules/create.md),
3) Functions in registered [packages] (optional)
Included are both native Rust as well as script-defined functions (except [`private`] ones).
Function Metadata
-----------------
Beware, however, that not all function signatures contain parameters and return value information.
### `Engine::register_XXX`
For instance, functions registered via `Engine::register_XXX` contain no information on
the names of parameter and their actual types because Rust simply does not make such metadata
available natively. The return type is also undetermined.
A function registered under the name 'foo' with three parameters and unknown return type:
> `foo(_, _, _)`
An operator function - again, unknown parameters and return type.
Notice that function names do not need to be valid identifiers.
> `+(_, _)`
A [property setter][getters/setters] - again, unknown parameters and return type.
Notice that function names do not need to be valid identifiers.
In this case, the first parameter should be '&mut T' of the custom type and the return value is '()':
> `set$prop(_, _, _)`
### Script-defined functions
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
the return value, are [`Dynamic`] the types are simply not shown.
A script-defined function always takes dynamic arguments, and the return type is also dynamic:
> `foo(x, y, z)`
probably defined as:
```rust
fn foo(x, y, z) {
...
}
```
is the same as:
> `foo(x: Dynamic, y: Dynamic, z: Dynamic) -> Result<Dynamic, Box<EvalAltResult>>`
### Plugin functions
Functions defined in [plugin modules] are the best. They contain all the metadata
describing the functions.
A plugin function `merge`:
> `merge(list: &mut MyStruct<i64>, num: usize, name: &str) -> Option<bool>`
Notice that function names do not need to be valid identifiers.
An operator defined as a [fallible function] in a [plugin module] via `#[rhai_fn(name="+=", return_raw)]`
returns `Result<bool, Box<EvalAltResult>>`:
> `+=(list: &mut MyStruct<i64>, num: usize, name: &str) -> Result<bool, Box<EvalAltResult>>`
A [property getter][getters/setters] defined in a [plugin module]:
> `get$prop(obj: &mut MyStruct<i64>) -> String`

View File

@ -101,21 +101,6 @@ a statement in the script can freely call a function defined afterwards.
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
`is_def_fn`
-----------
Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), based on its name
and the number of parameters.
```rust
fn foo(x) { x + 1 }
is_def_fn("foo", 1) == true;
is_def_fn("bar", 1) == false;
```
Arguments are Passed by Value
----------------------------
@ -159,3 +144,43 @@ x == 42; // 'x' is changed!
change(); // <- error: `this` is unbound
```
`is_def_fn`
-----------
Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), based on its name
and the number of parameters.
```rust
fn foo(x) { x + 1 }
is_def_fn("foo", 1) == true;
is_def_fn("bar", 1) == false;
```
Metadata
--------
The function `get_fn_metadata_list` is a _reflection_ API that returns an array of the metadata
of all script-defined functions in scope.
Functions from the following sources are returned, in order:
1) Encapsulated script environment (e.g. when loading a [module] from a script file),
2) Current script,
3) [Modules] imported via the [`import`] statement (latest imports first),
4) [Modules] added via [`Engine::register_module`]({{rootUrl}}/rust/modules/create.md) (latest registrations first)
The return value is an [array] of [object maps] (so `get_fn_metadata_list` is not available under
[`no_index`] or [`no_object`]), containing the following fields:
| Field | Type | Optional? | Description |
| -------------- | :------------------: | :-------: | ---------------------------------------------------------------------- |
| `namespace` | [string] | yes | the module _namespace_ if the function is defined within a module |
| `access` | [string] | no | `"public"` if the function is public,<br/>`"private"` if it is private |
| `name` | [string] | no | function name |
| `params` | [array] of [strings] | no | parameter names |
| `is_anonymous` | `bool` | no | is this function an anonymous function? |

View File

@ -32,7 +32,13 @@ a module's functionalities to Rhai.
use rhai::{Engine, Module};
let mut module = Module::new(); // new module
module.set_fn_1("inc", |x: i64| Ok(x+1)); // use the 'set_fn_XXX' API to add functions
// Use the 'set_fn_XXX' API to add functions.
let hash = module.set_fn_1("inc", |x: i64| Ok(x+1));
// Remember to update the parameter names/types and return type metadata.
// 'set_fn_XXX' by default does not set function metadata.
module.update_fn_metadata(hash, ["x: i64", "i64"]);
// Load the module into the Engine as a new package.
let mut engine = Engine::new();
@ -51,7 +57,13 @@ Make the `Module` a Global Module
use rhai::{Engine, Module};
let mut module = Module::new(); // new module
module.set_fn_1("inc", |x: i64| Ok(x+1)); // use the 'set_fn_XXX' API to add functions
// Use the 'set_fn_XXX' API to add functions.
let hash = module.set_fn_1("inc", |x: i64| Ok(x+1));
// Remember to update the parameter names/types and return type metadata.
// 'set_fn_XXX' by default does not set function metadata.
module.update_fn_metadata(hash, ["x: i64", "i64"]);
// Load the module into the Engine as a sub-module named 'calc'
let mut engine = Engine::new();
@ -71,9 +83,11 @@ use rhai::{Engine, Module, FnNamespace};
let mut module = Module::new(); // new module
// Expose method 'inc' to the global namespace (default is 'Internal')
module.set_fn_1_mut("inc", FnNamespace::Global,
|x: &mut i64| Ok(x+1)
);
let hash = module.set_fn_1_mut("inc", FnNamespace::Global, |x: &mut i64| Ok(x+1));
// Remember to update the parameter names/types and return type metadata.
// 'set_fn_XXX' by default does not set function metadata.
module.update_fn_metadata(hash, ["x: &mut i64", "i64"]);
// Load the module into the Engine as a sub-module named 'calc'
let mut engine = Engine::new();

View File

@ -50,9 +50,13 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
BasicMapPackage::init(module);
// Register additional Rust functions using the standard 'set_fn_XXX' module API.
module.set_fn_1("foo", |s: ImmutableString| {
let hash = module.set_fn_1("foo", |s: ImmutableString| {
Ok(foo(s.into_owned()))
});
// Remember to update the parameter names/types and return type metadata.
// 'set_fn_XXX' by default does not set function metadata.
module.update_fn_metadata(hash, ["s: ImmutableString", "i64"]);
});
```

View File

@ -89,7 +89,7 @@ impl fmt::Display for ScriptFnDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}{}({})",
"{}{}({}) -> Dynamic",
if self.access.is_private() {
"private "
} else {
@ -151,6 +151,7 @@ impl AST {
&mut self.0
}
/// Get the internal shared [`Module`] containing all script-defined functions.
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub(crate) fn shared_lib(&self) -> Shared<Module> {
self.1.clone()

View File

@ -97,11 +97,11 @@ impl Imports {
}
/// Get an iterator to this stack of imported modules in reverse order.
#[allow(dead_code)]
pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a {
self.0.iter().flat_map(|lib| {
lib.iter()
.rev()
.map(|(name, module)| (name.as_str(), module.clone()))
.map(|(name, module)| (name.clone(), module.clone()))
})
}
/// Get an iterator to this stack of imported modules in reverse order.

View File

@ -1650,10 +1650,10 @@ impl Engine {
}
/// Generate a list of all registered functions.
///
/// The ordering is:
/// Functions from the following sources are included, in order:
/// 1) Functions registered into the global namespace
/// 2) Functions in registered sub-modules
/// 3) Functions in packages
/// 3) Functions in packages (optional)
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
let mut signatures: Vec<_> = Default::default();

View File

@ -9,7 +9,7 @@ use crate::stdlib::{
boxed::Box,
collections::HashMap,
fmt, format,
iter::empty,
iter::{empty, once},
num::NonZeroUsize,
ops::{Add, AddAssign, Deref, DerefMut},
string::{String, ToString},
@ -90,8 +90,15 @@ impl FuncInfo {
let mut sig = format!("{}(", self.name);
if let Some(ref names) = self.param_names {
let params: Vec<_> = names.iter().map(ImmutableString::to_string).collect();
let mut params: Vec<_> = names.iter().map(ImmutableString::to_string).collect();
let return_type = params.pop().unwrap_or_else(|| "()".to_string());
sig.push_str(&params.join(", "));
if return_type != "()" {
sig.push_str(") -> ");
sig.push_str(&return_type);
} else {
sig.push_str(")");
}
} else {
for x in 0..self.params {
sig.push_str("_");
@ -99,9 +106,9 @@ impl FuncInfo {
sig.push_str(", ");
}
}
sig.push_str(") -> Dynamic");
}
sig.push_str(")");
sig
}
}
@ -362,7 +369,14 @@ impl Module {
access: fn_def.access,
params: num_params,
param_types: None,
param_names: Some(fn_def.params.clone()),
param_names: Some(
fn_def
.params
.iter()
.cloned()
.chain(once("Dynamic".into()))
.collect(),
),
func: fn_def.into(),
},
);
@ -483,13 +497,22 @@ impl Module {
}
}
/// Update the parameter names and types in a registered function.
/// Update the metadata (parameter names/types and return type) of a registered function.
///
/// The [`u64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
/// the function [`crate::calc_script_fn_hash`].
pub fn update_fn_param_names(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self {
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
/// The last entry in the list should be the return type of the function.
/// In other words, the number of entries should be one larger than the number of parameters.
pub fn update_fn_metadata<'a>(
&mut self,
hash_fn: u64,
arg_names: impl AsRef<[&'a str]>,
) -> &mut Self {
if let Some(f) = self.functions.get_mut(&hash_fn) {
f.param_names = Some(arg_names.iter().map(|&n| n.into()).collect());
f.param_names = Some(arg_names.as_ref().iter().map(|&n| n.into()).collect());
}
self
}
@ -573,6 +596,10 @@ impl Module {
///
/// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -632,6 +659,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -663,6 +694,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -696,6 +731,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -733,6 +772,10 @@ impl Module {
///
/// If there is a similar existing Rust getter function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -760,6 +803,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -799,6 +846,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -843,6 +894,10 @@ impl Module {
///
/// If there is a similar existing setter Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -880,6 +935,10 @@ impl Module {
/// Panics if the type is [`Array`] or [`Map`].
/// Indexers for arrays, object maps and strings cannot be registered.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -918,6 +977,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -963,6 +1026,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -1018,6 +1085,10 @@ impl Module {
/// Panics if the type is [`Array`] or [`Map`].
/// Indexers for arrays, object maps and strings cannot be registered.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -1079,6 +1150,10 @@ impl Module {
/// Panics if the type is [`Array`] or [`Map`].
/// Indexers for arrays, object maps and strings cannot be registered.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -1114,6 +1189,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -1166,6 +1245,10 @@ impl Module {
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
@ -1417,10 +1500,16 @@ impl Module {
)
}
/// Get an iterator to the sub-modules in the module.
#[inline(always)]
pub fn iter_sub_modules(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
self.modules.iter().map(|(k, m)| (k.as_str(), m.clone()))
}
/// Get an iterator to the variables in the module.
#[inline(always)]
pub fn iter_var(&self) -> impl Iterator<Item = (&String, &Dynamic)> {
self.variables.iter()
pub fn iter_var(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
self.variables.iter().map(|(k, v)| (k.as_str(), v))
}
/// Get an iterator to the functions in the module.

View File

@ -1,5 +1,11 @@
use crate::plugin::*;
use crate::{def_package, FnPtr};
use crate::stdlib::iter::empty;
use crate::{calc_script_fn_hash, def_package, FnPtr, ImmutableString, NativeCallContext, INT};
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
use crate::{module::SharedScriptFnDef, stdlib::collections::HashMap, Array, Map};
def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, {
combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions);
@ -13,10 +19,117 @@ mod fn_ptr_functions {
}
#[cfg(not(feature = "no_function"))]
pub mod anonymous {
pub mod functions {
#[rhai_fn(name = "is_anonymous", get = "is_anonymous")]
pub fn is_anonymous(f: &mut FnPtr) -> bool {
f.is_anonymous()
}
pub fn is_def_fn(ctx: NativeCallContext, fn_name: &str, num_params: INT) -> bool {
if num_params < 0 {
false
} else {
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
ctx.engine()
.has_override(ctx.mods, ctx.lib, 0, hash_script, true)
}
}
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
pub mod functions_and_maps {
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> Array {
collect_fn_metadata(ctx)
}
}
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
fn collect_fn_metadata(ctx: NativeCallContext) -> Array {
// Create a metadata record for a function.
fn make_metadata(
dict: &HashMap<&str, ImmutableString>,
namespace: Option<ImmutableString>,
f: SharedScriptFnDef,
) -> Map {
let mut map = Map::with_capacity(6);
if let Some(ns) = namespace {
map.insert(dict["namespace"].clone(), ns.into());
}
map.insert(dict["name"].clone(), f.name.clone().into());
map.insert(
dict["access"].clone(),
match f.access {
FnAccess::Public => dict["public"].clone(),
FnAccess::Private => dict["private"].clone(),
}
.into(),
);
map.insert(
dict["is_anonymous"].clone(),
f.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
);
map.insert(
dict["params"].clone(),
f.params
.iter()
.cloned()
.map(Into::<Dynamic>::into)
.collect::<Array>()
.into(),
);
map.into()
}
// Recursively scan modules for script-defined functions.
fn scan_module(
list: &mut Array,
dict: &HashMap<&str, ImmutableString>,
namespace: ImmutableString,
module: &Module,
) {
module.iter_script_fn().for_each(|(_, _, _, _, f)| {
list.push(make_metadata(dict, Some(namespace.clone()), f).into())
});
module.iter_sub_modules().for_each(|(ns, m)| {
let ns: ImmutableString = format!("{}::{}", namespace, ns).into();
scan_module(list, dict, ns, m.as_ref())
});
}
// Intern strings
let mut dict = HashMap::<&str, ImmutableString>::with_capacity(8);
[
"namespace",
"name",
"access",
"public",
"private",
"is_anonymous",
"params",
]
.iter()
.for_each(|&s| {
dict.insert(s, s.into());
});
let mut list: Array = Default::default();
ctx.lib
.iter()
.flat_map(|m| m.iter_script_fn())
.for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into()));
if let Some(mods) = ctx.mods {
mods.iter()
.for_each(|(ns, m)| scan_module(&mut list, &dict, ns, m.as_ref()));
}
list
}

View File

@ -49,7 +49,11 @@ macro_rules! reg_range {
$(
$lib.set_iterator::<Range<$y>>();
let hash = $lib.set_fn_2($x, get_range::<$y>);
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y))]);
$lib.update_fn_metadata(hash, [
concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)),
concat!("Iterator<Item=", stringify!($y), ">")
]);
)*
)
}
@ -61,7 +65,11 @@ macro_rules! reg_step {
$(
$lib.set_iterator::<StepRange<$y>>();
let hash = $lib.set_fn_3($x, get_step_range::<$y>);
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y))]);
$lib.update_fn_metadata(hash, [
concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)),
concat!("step: ", stringify!($y)), concat!("Iterator<Item=", stringify!($y), ">")
]);
)*
)
}
@ -69,7 +77,7 @@ macro_rules! reg_step {
def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<Range<INT>>();
let hash = lib.set_fn_2("range", get_range::<INT>);
lib.update_fn_param_names(hash, &["from: INT", "to: INT"]);
lib.update_fn_metadata(hash, ["from: INT", "to: INT", "Iterator<Item=INT>"]);
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
@ -83,7 +91,7 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<StepRange<INT>>();
let hash = lib.set_fn_3("range", get_step_range::<INT>);
lib.update_fn_param_names(hash, &["from: INT", "to: INT", "step: INT"]);
lib.update_fn_metadata(hash, ["from: INT", "to: INT", "step: INT", "Iterator<Item=INT>"]);
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]

View File

@ -4,34 +4,9 @@ use super::iter_basic::BasicIteratorPackage;
use super::logic::LogicPackage;
use super::string_basic::BasicStringPackage;
use crate::fn_native::{CallableFunction, FnCallArgs};
use crate::stdlib::{any::TypeId, boxed::Box, iter::empty};
use crate::{
calc_script_fn_hash, def_package, FnAccess, FnNamespace, ImmutableString, NativeCallContext,
INT,
};
use crate::def_package;
def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, {
#[cfg(not(feature = "no_function"))]
{
let f = |ctx: NativeCallContext, args: &mut FnCallArgs| {
let num_params = args[1].clone().cast::<INT>();
let fn_name = args[0].as_str().unwrap();
Ok(if num_params < 0 {
false.into()
} else {
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
ctx.engine().has_override(ctx.mods, ctx.lib, 0, hash_script, true).into()
})
};
lib.set_fn("is_def_fn", FnNamespace::Global, FnAccess::Public,
Some(&["fn_name: &str", "num_params: INT"]),
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()],
CallableFunction::from_method(Box::new(f)));
}
ArithmeticPackage::init(lib);
LogicPackage::init(lib);
BasicStringPackage::init(lib);

View File

@ -38,4 +38,7 @@ pub trait PluginFunction {
/// Return a boxed slice of type ID's of the function's parameters.
fn input_types(&self) -> Box<[TypeId]>;
/// Return a string slice of the function's return type.
fn return_type(&self) -> &'static str;
}