diff --git a/CHANGELOG.md b/CHANGELOG.md index b5731b58f..014d5f2a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ Fixes to bugs found via fuzzing * Fixed improper parsing of numbers with too many decimal points. * Fixed exponential running time when raising a decimal number to a very large power (> 1 million) -- it now returns an overflow error. * Shared values that contain reference loops no longer cause a stack overflow when printing. +* `sleep` no longer panics on `NaN`. +* `switch` on ranges now work properly. Other bug fixes --------------- @@ -47,7 +49,11 @@ Other bug fixes New features ------------ +* `#[derive(CustomType)]` is now available, driven by procedural macros in `rhai_codegen`. +* A new `FuncRegistration` API is added to assist in registering native Rust functions into modules with various settings. Some of the original `Module::set_fn...` API is now deprecated. * Functions defined in plugin modules can now be marked as `volatile` which prevents it from being optimized away even under `OptimizationLevel::Full`. +* Added `Engine::max_functions` and `Engine::set_max_functions` to limit the maximum number of functions allowed in a script. This s to guard against DOS attacks -- e.g. a simple closure `||` (two characters) is a function. When `max_function` is exceeded during script compilation, a new parse error, `TooManyFunctions`, is returned. +* `Engine::get_interned_string` is made public instead of gated under `internals`. Enhancements ------------ @@ -57,6 +63,7 @@ Enhancements * `Token::FloatConstant` and `Token::DecimalConstant` now carry the original text representation for use in, say, a _token mapper_. * `Dynamic::is_fnptr` is made a public API. * `Scope::get_value_ref` and `Scope::get_value_mut` are added. +* `TypeBuilder::with_name` now takes any `&str` instead of just `&'static str`. Version 1.16.3 diff --git a/Cargo.toml b/Cargo.toml index e4f4da67a..615c78696 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ num-traits = { version = "0.2.0", default-features = false } once_cell = { version = "1.7.0", default-features = false, features = ["race"] } bitflags = { version = "2.0.0", default-features = false } smartstring = { version = "1.0.0", default-features = false } -rhai_codegen = { version = "1.7.0", path = "codegen" } +rhai_codegen = { version = "1.17.0", path = "codegen" } no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat", version = "0.4.1", default-features = false, features = ["alloc"], optional = true } libm = { version = "0.2.0", default-features = false, optional = true } @@ -165,3 +165,6 @@ features = ["document-features", "metadata", "serde", "internals", "decimal", "d # Notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows. # This can be moved to the official version when bracketed paste is added. rustyline = { git = "https://github.com/schungx/rustyline", branch = "v13" } + +# Patch SmartString to resolve an UB issue. +smartstring = { git = "https://github.com/bodil/smartstring", ref = "refs/pull/34/head" } diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 4c79d58ec..96b3d7ce8 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai_codegen" -version = "1.7.0" +version = "1.17.0" edition = "2018" resolver = "2" authors = ["jhwgh1968", "Stephen Chung"] diff --git a/codegen/src/custom_type.rs b/codegen/src/custom_type.rs index 8b08af1fb..7982e5056 100644 --- a/codegen/src/custom_type.rs +++ b/codegen/src/custom_type.rs @@ -48,7 +48,7 @@ pub fn derive_custom_type_impl(input: DeriveInput) -> TokenStream { quote! { impl ::rhai::CustomType for #name { - fn build(mut builder: ::rhai::TypeBuilder<'_, Self>) { + fn build(mut builder: ::rhai::TypeBuilder) { #accessors; } } diff --git a/codegen/src/function.rs b/codegen/src/function.rs index c377a8034..8f474d4cc 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -854,7 +854,7 @@ impl ExportedFn { #[inline(always)] pub fn param_types() -> [TypeId; #arg_count] { [#(#input_type_exprs),*] } } #(#cfg_attrs)* - impl PluginFunction for #type_name { + impl PluginFunc for #type_name { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { #(#unpack_statements)* diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 09469d3b9..29088aaa1 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -345,19 +345,18 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream Ok((module_expr, export_name, rust_mod_path)) => { let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - #[cfg(feature = "metadata")] - let param_names = quote! { - Some(#gen_mod_path::Token::PARAM_NAMES) + let mut tokens = quote! { + let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Internal) }; - #[cfg(not(feature = "metadata"))] - let param_names = quote! { None }; - - proc_macro::TokenStream::from(quote! { - #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, - #param_names, - &#gen_mod_path::Token::param_types(), - #gen_mod_path::Token().into()) - }) + #[cfg(feature = "metadata")] + tokens.extend(quote! { + .with_params_info(#gen_mod_path::Token::PARAM_NAMES) + }); + tokens.extend(quote! { + ; + #module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into()); + }); + tokens.into() } Err(e) => e.to_compile_error().into(), } @@ -394,19 +393,18 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke Ok((module_expr, export_name, rust_mod_path)) => { let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - #[cfg(feature = "metadata")] - let param_names = quote! { - Some(#gen_mod_path::Token::PARAM_NAMES) + let mut tokens = quote! { + let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Global) }; - #[cfg(not(feature = "metadata"))] - let param_names = quote! { None }; - - proc_macro::TokenStream::from(quote! { - #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, - #param_names, - &#gen_mod_path::Token::param_types(), - #gen_mod_path::Token().into()) - }) + #[cfg(feature = "metadata")] + tokens.extend(quote! { + .with_params_info(#gen_mod_path::Token::PARAM_NAMES) + }); + tokens.extend(quote! { + ; + #module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into()); + }); + tokens.into() } Err(e) => e.to_compile_error().into(), } diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index b04d88a81..903b82ff7 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -5,8 +5,8 @@ use std::collections::BTreeMap; use crate::attrs::ExportScope; use crate::function::{ - flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET, - FN_IDX_GET, FN_IDX_SET, FN_SET, + print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET, FN_IDX_GET, FN_IDX_SET, + FN_SET, }; use crate::module::Module; @@ -39,8 +39,6 @@ pub fn generate_body( let mut set_const_statements = Vec::new(); let mut add_mod_blocks = Vec::new(); let mut set_flattened_mod_blocks = Vec::new(); - let str_type_path = syn::parse2::(quote! { str }).unwrap(); - let string_type_path = syn::parse2::(quote! { String }).unwrap(); for ExportedConst { name: const_name, @@ -146,49 +144,6 @@ pub fn generate_body( ); let reg_names = function.exported_names(); - let fn_input_types: Vec<_> = function - .arg_list() - .map(|fn_arg| match fn_arg { - syn::FnArg::Receiver(..) => unreachable!("receiver fn outside impl!?"), - syn::FnArg::Typed(syn::PatType { ref ty, .. }) => { - let arg_type = match flatten_type_groups(ty.as_ref()) { - syn::Type::Reference(syn::TypeReference { - mutability: None, - ref elem, - .. - }) => match flatten_type_groups(elem.as_ref()) { - syn::Type::Path(ref p) if p.path == str_type_path => { - syn::parse2::(quote! { - ImmutableString }) - .unwrap() - } - _ => unreachable!("non-string shared reference!?"), - }, - syn::Type::Path(ref p) if p.path == string_type_path => { - syn::parse2::(quote! { - ImmutableString }) - .unwrap() - } - syn::Type::Reference(syn::TypeReference { - mutability: Some(_), - ref elem, - .. - }) => match flatten_type_groups(elem.as_ref()) { - syn::Type::Path(ref p) => syn::parse2::(quote! { - #p }) - .unwrap(), - _ => unreachable!("invalid mutable reference!?"), - }, - t => t.clone(), - }; - - syn::parse2::(quote! { - TypeId::of::<#arg_type>()}) - .unwrap() - } - }) - .collect(); - let cfg_attrs: Vec<_> = function .cfg_attrs() .iter() @@ -226,33 +181,34 @@ pub fn generate_body( fn_literal.span(), ); + let mut tokens = quote! { + #(#cfg_attrs)* + FuncRegistration::new(#fn_literal).with_namespace(FnNamespace::#ns_str) + }; #[cfg(feature = "metadata")] - let (param_names, comments) = ( - quote! { Some(#fn_token_name::PARAM_NAMES) }, - function + { + tokens.extend(quote! { + .with_params_info(#fn_token_name::PARAM_NAMES) + }); + + let comments = function .comments() .iter() .map(|s| syn::LitStr::new(s, Span::call_site())) - .collect::>(), - ); - #[cfg(not(feature = "metadata"))] - let (param_names, comments) = (quote! { None }, Vec::::new()); + .collect::>(); - set_fn_statements.push(if comments.is_empty() { - syn::parse2::(quote! { - #(#cfg_attrs)* - m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, - #param_names, &[#(#fn_input_types),*], #fn_token_name().into()); - }) - .unwrap() - } else { - syn::parse2::(quote! { - #(#cfg_attrs)* - m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, - #param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into()); - }) - .unwrap() + if !comments.is_empty() { + tokens.extend(quote! { + .with_comments(&[#(#comments),*]) + }); + } + } + + tokens.extend(quote! { + .set_into_module_raw(m, &#fn_token_name::param_types(), #fn_token_name().into()); }); + + set_fn_statements.push(syn::parse2::(tokens).unwrap()); } gen_fn_tokens.push(quote! { diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index f07a4cb20..c3e1b47e7 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -279,7 +279,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["()"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(do_nothing())) } @@ -318,7 +318,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -359,7 +359,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -403,7 +403,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["rhai::Dynamic"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(return_dynamic())) @@ -438,7 +438,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for TestStruct { + impl PluginFunc for TestStruct { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -473,7 +473,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "y: usize", "usize"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -515,7 +515,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut usize", "y: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -558,7 +558,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["message: &str", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for Token { + impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap(); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 4a0ce94b1..a2764734b 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -378,9 +378,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, - Some(get_mystic_number_token::PARAM_NAMES), &[], - get_mystic_number_token().into()); + FuncRegistration::new("get_mystic_number").with_namespace(FnNamespace::Internal).with_params_info(get_mystic_number_token::PARAM_NAMES) + .set_into_module_raw(m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -391,7 +390,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } - impl PluginFunction for get_mystic_number_token { + impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) @@ -473,11 +472,12 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn_with_comments("get_mystic_number", FnNamespace::Internal, FnAccess::Public, - Some(get_mystic_number_token::PARAM_NAMES), &[], &[ - "/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.", - "/** doc-comment\n in multiple lines\n */" - ], get_mystic_number_token().into()); + FuncRegistration::new("get_mystic_number").with_namespace(FnNamespace::Internal).with_params_info(get_mystic_number_token::PARAM_NAMES) + .with_comments(&[ + "/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.", + "/** doc-comment\n in multiple lines\n */" + ]) + .set_into_module_raw(m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); m.set_custom_type_with_comments::("World", &["/// We are the world!"]); if flatten {} else {} } @@ -489,7 +489,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } - impl PluginFunction for get_mystic_number_token { + impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) @@ -537,9 +537,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, - Some(add_one_to_token::PARAM_NAMES), &[TypeId::of::()], - add_one_to_token().into()); + FuncRegistration::new("add_one_to").with_namespace(FnNamespace::Global).with_params_info(add_one_to_token::PARAM_NAMES) + .set_into_module_raw(m, &add_one_to_token::param_types(), add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -550,7 +549,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for add_one_to_token { + impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -598,9 +597,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(add_one_to_token::PARAM_NAMES), - &[TypeId::of::()], - add_one_to_token().into()); + FuncRegistration::new("add_one_to").with_namespace(FnNamespace::Internal).with_params_info(add_one_to_token::PARAM_NAMES) + .set_into_module_raw(m, &add_one_to_token::param_types(), add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -611,7 +609,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for add_one_to_token { + impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -670,12 +668,10 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(add_one_to_token::PARAM_NAMES), - &[TypeId::of::()], - add_one_to_token().into()); - m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(add_n_to_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - add_n_to_token().into()); + FuncRegistration::new("add_n").with_namespace(FnNamespace::Internal).with_params_info(add_one_to_token::PARAM_NAMES) + .set_into_module_raw(m, &add_one_to_token::param_types(), add_one_to_token().into()); + FuncRegistration::new("add_n").with_namespace(FnNamespace::Internal).with_params_info(add_n_to_token::PARAM_NAMES) + .set_into_module_raw(m, &add_n_to_token::param_types(), add_n_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -686,7 +682,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for add_one_to_token { + impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -707,7 +703,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for add_n_to_token { + impl PluginFunc for add_n_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -756,9 +752,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - add_together_token().into()); + FuncRegistration::new("add_together").with_namespace(FnNamespace::Internal).with_params_info(add_together_token::PARAM_NAMES) + .set_into_module_raw(m, &add_together_token::param_types(), add_together_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -769,7 +764,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for add_together_token { + impl PluginFunc for add_together_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -819,15 +814,12 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - add_together_token().into()); - m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - add_together_token().into()); - m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - add_together_token().into()); + FuncRegistration::new("add").with_namespace(FnNamespace::Internal).with_params_info(add_together_token::PARAM_NAMES) + .set_into_module_raw(m, &add_together_token::param_types(), add_together_token().into()); + FuncRegistration::new("+").with_namespace(FnNamespace::Internal).with_params_info(add_together_token::PARAM_NAMES) + .set_into_module_raw(m, &add_together_token::param_types(), add_together_token().into()); + FuncRegistration::new("add_together").with_namespace(FnNamespace::Internal).with_params_info(add_together_token::PARAM_NAMES) + .set_into_module_raw(m, &add_together_token::param_types(), add_together_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -838,7 +830,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for add_together_token { + impl PluginFunc for add_together_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); @@ -901,9 +893,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, - Some(get_mystic_number_token::PARAM_NAMES), &[TypeId::of::()], - get_mystic_number_token().into()); + FuncRegistration::new("get_mystic_number").with_namespace(FnNamespace::Internal).with_params_info(get_mystic_number_token::PARAM_NAMES) + .set_into_module_raw(m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); m.set_custom_type::("Hello"); if flatten {} else {} @@ -917,7 +908,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut Hello", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for get_mystic_number_token { + impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1121,9 +1112,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, - Some(get_mystic_number_token::PARAM_NAMES), &[], - get_mystic_number_token().into()); + FuncRegistration::new("get_mystic_number").with_namespace(FnNamespace::Internal).with_params_info(get_mystic_number_token::PARAM_NAMES) + .set_into_module_raw(m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1134,7 +1124,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } - impl PluginFunction for get_mystic_number_token { + impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) @@ -1215,9 +1205,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(print_out_to_token::PARAM_NAMES), - &[TypeId::of::()], - print_out_to_token().into()); + FuncRegistration::new("print_out_to").with_namespace(FnNamespace::Internal).with_params_info(print_out_to_token::PARAM_NAMES) + .set_into_module_raw(m, &print_out_to_token::param_types(), print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1228,7 +1217,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &str", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for print_out_to_token { + impl PluginFunc for print_out_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap(); @@ -1276,9 +1265,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(print_out_to_token::PARAM_NAMES), - &[TypeId::of::()], - print_out_to_token().into()); + FuncRegistration::new("print_out_to").with_namespace(FnNamespace::Internal).with_params_info(print_out_to_token::PARAM_NAMES) + .set_into_module_raw(m, &print_out_to_token::param_types(), print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1289,7 +1277,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: String", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for print_out_to_token { + impl PluginFunc for print_out_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_string().unwrap(); @@ -1338,9 +1326,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("foo", FnNamespace::Internal, FnAccess::Public, Some(foo_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - foo_token().into()); + FuncRegistration::new("foo").with_namespace(FnNamespace::Internal).with_params_info(foo_token::PARAM_NAMES) + .set_into_module_raw(m, &foo_token::param_types(), foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1351,7 +1338,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "y: INT", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for foo_token { + impl PluginFunc for foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -1400,9 +1387,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), - &[TypeId::of::()], - increment_token().into()); + FuncRegistration::new("increment").with_namespace(FnNamespace::Internal).with_params_info(increment_token::PARAM_NAMES) + .set_into_module_raw(m, &increment_token::param_types(), increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1413,7 +1399,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for increment_token { + impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1465,9 +1451,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), - &[TypeId::of::()], - increment_token().into()); + FuncRegistration::new("increment").with_namespace(FnNamespace::Internal).with_params_info(increment_token::PARAM_NAMES) + .set_into_module_raw(m, &increment_token::param_types(), increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1478,7 +1463,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for increment_token { + impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1552,9 +1537,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), - &[TypeId::of::()], - increment_token().into()); + FuncRegistration::new("increment").with_namespace(FnNamespace::Internal).with_params_info(increment_token::PARAM_NAMES) + .set_into_module_raw(m, &increment_token::param_types(), increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1565,7 +1549,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for increment_token { + impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1640,9 +1624,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::()], - int_foo_token().into()); + FuncRegistration::new("get$square").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1653,7 +1636,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "u64"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for int_foo_token { + impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1702,12 +1685,10 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::()], - int_foo_token().into()); - m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::()], - int_foo_token().into()); + FuncRegistration::new("square").with_namespace(FnNamespace::Internal).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); + FuncRegistration::new("get$square").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1718,7 +1699,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "u64"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } - impl PluginFunction for int_foo_token { + impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -1767,9 +1748,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - int_foo_token().into()); + FuncRegistration::new("set$squared").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1780,7 +1760,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "y: u64", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for int_foo_token { + impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -1830,12 +1810,10 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - int_foo_token().into()); - m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - int_foo_token().into()); + FuncRegistration::new("set_sq").with_namespace(FnNamespace::Internal).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); + FuncRegistration::new("set$squared").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) + .set_into_module_raw(m, &int_foo_token::param_types(), int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1846,7 +1824,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "y: u64", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for int_foo_token { + impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -1896,9 +1874,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(get_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - get_by_index_token().into()); + FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &get_by_index_token::param_types(), get_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -1909,7 +1886,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for get_by_index_token { + impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -1964,9 +1941,8 @@ mod generate_tests { #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { #[cfg(hello)] - m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(get_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - get_by_index_token().into()); + FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &get_by_index_token::param_types(), get_by_index_token().into()); if flatten {} else {} } #[cfg(hello)] @@ -1980,7 +1956,7 @@ mod generate_tests { #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } #[cfg(hello)] - impl PluginFunction for get_by_index_token { + impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -2030,12 +2006,10 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get", FnNamespace::Internal, FnAccess::Public, Some(get_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - get_by_index_token().into()); - m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(get_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::()], - get_by_index_token().into()); + FuncRegistration::new("get").with_namespace(FnNamespace::Internal).with_params_info(get_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &get_by_index_token::param_types(), get_by_index_token().into()); + FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &get_by_index_token::param_types(), get_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -2046,7 +2020,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for get_by_index_token { + impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -2096,9 +2070,8 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$set$", FnNamespace::Global, FnAccess::Public, Some(set_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::(), TypeId::of::()], - set_by_index_token().into()); + FuncRegistration::new("index$set$").with_namespace(FnNamespace::Global).with_params_info(set_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &set_by_index_token::param_types(), set_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -2109,7 +2082,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 3usize] { [TypeId::of::(), TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for set_by_index_token { + impl PluginFunc for set_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); @@ -2160,12 +2133,10 @@ mod generate_tests { #[allow(unused_mut)] #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set", FnNamespace::Internal, FnAccess::Public, Some(set_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::(), TypeId::of::()], - set_by_index_token().into()); - m.set_fn("index$set$", FnNamespace::Global, FnAccess::Public, Some(set_by_index_token::PARAM_NAMES), - &[TypeId::of::(), TypeId::of::(), TypeId::of::()], - set_by_index_token().into()); + FuncRegistration::new("set").with_namespace(FnNamespace::Internal).with_params_info(set_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &set_by_index_token::param_types(), set_by_index_token().into()); + FuncRegistration::new("index$set$").with_namespace(FnNamespace::Global).with_params_info(set_by_index_token::PARAM_NAMES) + .set_into_module_raw(m, &set_by_index_token::param_types(), set_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] @@ -2176,7 +2147,7 @@ mod generate_tests { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 3usize] { [TypeId::of::(), TypeId::of::(), TypeId::of::()] } } - impl PluginFunction for set_by_index_token { + impl PluginFunc for set_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); diff --git a/fuzz/clusterfuzz-testcase-fuzz_serde-4745120863813632 b/fuzz/clusterfuzz-testcase-fuzz_serde-4745120863813632 new file mode 100644 index 000000000..10677e9d5 Binary files /dev/null and b/fuzz/clusterfuzz-testcase-fuzz_serde-4745120863813632 differ diff --git a/fuzz/clusterfuzz-testcase-scripting-4756460147900416 b/fuzz/clusterfuzz-testcase-scripting-4756460147900416 new file mode 100644 index 000000000..8ef14c69e --- /dev/null +++ b/fuzz/clusterfuzz-testcase-scripting-4756460147900416 @@ -0,0 +1 @@ +55>>-666+66666+e66+-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|kbbbbbbbbbbbbbbbbbbbbbbb|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||f||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pn-oo||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|ppp|-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||ppppxpppppp|oo|o|k|pppppo;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|yitsTTTTTTpppppn-||||||||||||o;||||47>>-666+128+e66+-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||f||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-O||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|pppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||ppppxpppppp|oo|o|k|pppppo;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|yitsTTTTTTpppppn-||||||||||||o;||||-+n-||||||||||||o;||||!oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||fo;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||z|oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|pk|ppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o||||o;||||-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o||||o;||||-+n-||||||||||||o;|||||oo|o|k|ppppp||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-+n-||||||||||-||o;|||||oo|o|k|pppppn-||||||||||||o;||||-+n-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppn-||||||||||||o;|||||oo|o|k|pppppp+o|k|pppppp+n-||||||||||||o;|||||oo|o|k|ppp \ No newline at end of file diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 5b5e77a66..6d1e37a8a 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -1,7 +1,7 @@ //! Trait to build a custom type for use with [`Engine`]. use crate::func::SendSync; use crate::packages::string_basic::{FUNC_TO_DEBUG, FUNC_TO_STRING}; -use crate::{types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction}; +use crate::{types::dynamic::Variant, Engine, Identifier, RhaiNativeFunc}; use std::marker::PhantomData; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -98,13 +98,13 @@ impl Engine { /// /// To define a pretty-print name, call [`with_name`][`TypeBuilder::with_name`], /// to use [`Engine::register_type_with_name`] instead. -pub struct TypeBuilder<'a, T: Variant + Clone> { +pub struct TypeBuilder<'a, 's, T: Variant + Clone> { engine: &'a mut Engine, - name: Option<&'static str>, + name: Option<&'s str>, _marker: PhantomData, } -impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { +impl<'a, T: Variant + Clone> TypeBuilder<'a, '_, T> { /// Create a [`TypeBuilder`] linked to a particular [`Engine`] instance. #[inline(always)] fn new(engine: &'a mut Engine) -> Self { @@ -116,11 +116,11 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { } } -impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { +impl<'s, T: Variant + Clone> TypeBuilder<'_, 's, T> { /// Set a pretty-print name for the `type_of` function. #[inline(always)] - pub fn with_name(&mut self, name: &'static str) -> &mut Self { - self.name = Some(name); + pub fn with_name(&mut self, name: &'s str) -> &mut Self { + self.name = Some(name.as_ref()); self } @@ -146,17 +146,17 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Register a custom function. #[inline(always)] - pub fn with_fn( + pub fn with_fn( &mut self, name: impl AsRef + Into, - method: impl RegisterNativeFunction + SendSync + 'static, + method: impl RhaiNativeFunc + SendSync + 'static, ) -> &mut Self { self.engine.register_fn(name, method); self } } -impl<'a, T> TypeBuilder<'a, T> +impl TypeBuilder<'_, '_, T> where T: Variant + Clone + IntoIterator, ::Item: Variant + Clone, @@ -171,17 +171,17 @@ where } #[cfg(not(feature = "no_object"))] -impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { +impl TypeBuilder<'_, '_, T> { /// Register a getter function. /// /// The function signature must start with `&mut self` and not `&self`. /// /// Not available under `no_object`. #[inline(always)] - pub fn with_get( + pub fn with_get( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C, V, L> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, F> + SendSync + 'static, ) -> &mut Self { self.engine.register_get(name, get_fn); self @@ -191,10 +191,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// /// Not available under `no_object`. #[inline(always)] - pub fn with_set( + pub fn with_set( &mut self, name: impl AsRef, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C, (), L> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, R), 2, X, (), F> + SendSync + 'static, ) -> &mut Self { self.engine.register_set(name, set_fn); self @@ -207,16 +207,16 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Not available under `no_object`. #[inline(always)] pub fn with_get_set< - const C1: bool, - const C2: bool, - V: Variant + Clone, - const L1: bool, - const L2: bool, + const X1: bool, + const X2: bool, + R: Variant + Clone, + const F1: bool, + const F2: bool, >( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C1, V, L1> + SendSync + 'static, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C2, (), L2> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X1, R, F1> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, R), 2, X2, (), F2> + SendSync + 'static, ) -> &mut Self { self.engine.register_get_set(name, get_fn, set_fn); self @@ -224,7 +224,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { +impl TypeBuilder<'_, '_, T> { /// Register an index getter. /// /// The function signature must start with `&mut self` and not `&self`. @@ -232,13 +232,13 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Not available under both `no_index` and `no_object`. #[inline(always)] pub fn with_indexer_get< - X: Variant + Clone, - const C: bool, - V: Variant + Clone, - const L: bool, + IDX: Variant + Clone, + const X: bool, + R: Variant + Clone, + const F: bool, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C, V, L> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X, R, F> + SendSync + 'static, ) -> &mut Self { self.engine.register_indexer_get(get_fn); self @@ -249,13 +249,13 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Not available under both `no_index` and `no_object`. #[inline(always)] pub fn with_indexer_set< - X: Variant + Clone, - const C: bool, - V: Variant + Clone, - const L: bool, + IDX: Variant + Clone, + const X: bool, + R: Variant + Clone, + const F: bool, >( &mut self, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C, (), L> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X, (), F> + SendSync + 'static, ) -> &mut Self { self.engine.register_indexer_set(set_fn); self @@ -266,27 +266,27 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// Not available under both `no_index` and `no_object`. #[inline(always)] pub fn with_indexer_get_set< - X: Variant + Clone, - const C1: bool, - const C2: bool, - V: Variant + Clone, - const L1: bool, - const L2: bool, + IDX: Variant + Clone, + const X1: bool, + const X2: bool, + R: Variant + Clone, + const F1: bool, + const F2: bool, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C1, V, L1> + SendSync + 'static, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C2, (), L2> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X1, R, F1> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X2, (), F2> + SendSync + 'static, ) -> &mut Self { self.engine.register_indexer_get_set(get_fn, set_fn); self } } -impl<'a, T: Variant + Clone> Drop for TypeBuilder<'a, T> { +impl Drop for TypeBuilder<'_, '_, T> { #[inline] fn drop(&mut self) { match self.name { - Some(name) => self.engine.register_type_with_name::(name), + Some(ref name) => self.engine.register_type_with_name::(name), None => self.engine.register_type::(), }; } diff --git a/src/api/definitions/mod.rs b/src/api/definitions/mod.rs index abd373804..2d7391f08 100644 --- a/src/api/definitions/mod.rs +++ b/src/api/definitions/mod.rs @@ -2,7 +2,7 @@ #![cfg(feature = "internals")] #![cfg(feature = "metadata")] -use crate::module::{FuncInfo, ModuleFlags}; +use crate::module::{FuncMetadata, ModuleFlags}; use crate::tokenizer::{is_valid_function_name, Token}; use crate::{Engine, FnAccess, FnPtr, Module, Scope, INT}; @@ -436,29 +436,26 @@ impl Module { } let mut func_infos = self.iter_fn().collect::>(); - func_infos.sort_by(|a, b| match a.metadata.name.cmp(&b.metadata.name) { - Ordering::Equal => match a.metadata.num_params.cmp(&b.metadata.num_params) { - Ordering::Equal => (a.metadata.params_info.join("") - + a.metadata.return_type.as_str()) - .cmp(&(b.metadata.params_info.join("") + b.metadata.return_type.as_str())), + func_infos.sort_by(|(_, a), (_, b)| match a.name.cmp(&b.name) { + Ordering::Equal => match a.num_params.cmp(&b.num_params) { + Ordering::Equal => (a.params_info.join("") + a.return_type.as_str()) + .cmp(&(b.params_info.join("") + b.return_type.as_str())), o => o, }, o => o, }); - for f in func_infos { + for (_, f) in func_infos { if !first { writer.write_str("\n\n")?; } first = false; - if f.metadata.access != FnAccess::Private { - let operator = - !f.metadata.name.contains('$') && !is_valid_function_name(&f.metadata.name); + if f.access != FnAccess::Private { + let operator = !f.name.contains('$') && !is_valid_function_name(&f.name); #[cfg(not(feature = "no_custom_syntax"))] - let operator = - operator || def.engine.custom_keywords.contains_key(&f.metadata.name); + let operator = operator || def.engine.custom_keywords.contains_key(&f.name); f.write_definition(writer, def, operator)?; } @@ -468,7 +465,7 @@ impl Module { } } -impl FuncInfo { +impl FuncMetadata { /// Output definitions for a function. fn write_definition( &self, @@ -476,7 +473,7 @@ impl FuncInfo { def: &Definitions, operator: bool, ) -> fmt::Result { - for comment in &*self.metadata.comments { + for comment in &*self.comments { writeln!(writer, "{comment}")?; } @@ -486,33 +483,29 @@ impl FuncInfo { writer.write_str("fn ")?; } - if let Some(name) = self.metadata.name.strip_prefix("get$") { + if let Some(name) = self.name.strip_prefix("get$") { write!(writer, "get {name}(")?; - } else if let Some(name) = self.metadata.name.strip_prefix("set$") { + } else if let Some(name) = self.name.strip_prefix("set$") { write!(writer, "set {name}(")?; } else { - write!(writer, "{}(", self.metadata.name)?; + write!(writer, "{}(", self.name)?; } let mut first = true; - for i in 0..self.metadata.num_params { + for i in 0..self.num_params { if !first { writer.write_str(", ")?; } first = false; - let (param_name, param_type) = - self.metadata - .params_info - .get(i) - .map_or(("_", "?".into()), |s| { - let mut s = s.splitn(2, ':'); - ( - s.next().unwrap_or("_").split(' ').last().unwrap(), - s.next() - .map_or(Cow::Borrowed("?"), |ty| def_type_name(ty, def.engine)), - ) - }); + let (param_name, param_type) = self.params_info.get(i).map_or(("_", "?".into()), |s| { + let mut s = s.splitn(2, ':'); + ( + s.next().unwrap_or("_").split(' ').last().unwrap(), + s.next() + .map_or(Cow::Borrowed("?"), |ty| def_type_name(ty, def.engine)), + ) + }); if operator { write!(writer, "{param_type}")?; @@ -524,7 +517,7 @@ impl FuncInfo { write!( writer, ") -> {};", - def_type_name(&self.metadata.return_type, def.engine) + def_type_name(&self.return_type, def.engine) )?; Ok(()) diff --git a/src/api/deprecated.rs b/src/api/deprecated.rs index 2e2aec065..17248b62c 100644 --- a/src/api/deprecated.rs +++ b/src/api/deprecated.rs @@ -1,12 +1,13 @@ //! Module containing all deprecated API that will be removed in the next major version. -use crate::func::SendSync; +use crate::func::{RhaiFunc, SendSync}; use crate::types::dynamic::Variant; use crate::{ - Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, NativeCallContext, - Position, RegisterNativeFunction, RhaiResult, RhaiResultOf, Scope, SharedModule, TypeBuilder, - AST, + Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, FnPtr, FuncRegistration, Identifier, + ImmutableString, Module, NativeCallContext, Position, RhaiNativeFunc, RhaiResult, RhaiResultOf, + Scope, SharedModule, TypeBuilder, AST, }; +use std::any::TypeId; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -195,10 +196,10 @@ impl Engine { /// This method will be removed in the next major version. #[deprecated(since = "1.9.1", note = "use `register_fn` instead")] #[inline(always)] - pub fn register_result_fn( + pub fn register_result_fn( &mut self, name: impl AsRef + Into, - func: impl RegisterNativeFunction + SendSync + 'static, + func: impl RhaiNativeFunc + SendSync + 'static, ) -> &mut Self { self.register_fn(name, func) } @@ -217,10 +218,10 @@ impl Engine { #[deprecated(since = "1.9.1", note = "use `register_get` instead")] #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_get_result( + pub fn register_get_result( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C, V, true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, true> + SendSync + 'static, ) -> &mut Self { self.register_get(name, get_fn) } @@ -237,10 +238,10 @@ impl Engine { #[deprecated(since = "1.9.1", note = "use `register_set` instead")] #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_set_result( + pub fn register_set_result( &mut self, name: impl AsRef, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C, (), true> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, V), 2, X, (), true> + SendSync + 'static, ) -> &mut Self { self.register_set(name, set_fn) } @@ -261,12 +262,12 @@ impl Engine { #[inline(always)] pub fn register_indexer_get_result< T: Variant + Clone, - X: Variant + Clone, - V: Variant + Clone, - const C: bool, + IDX: Variant + Clone, + R: Variant + Clone, + const X: bool, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C, V, true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X, R, true> + SendSync + 'static, ) -> &mut Self { self.register_indexer_get(get_fn) } @@ -285,12 +286,12 @@ impl Engine { #[inline(always)] pub fn register_indexer_set_result< T: Variant + Clone, - X: Variant + Clone, - V: Variant + Clone, - const C: bool, + IDX: Variant + Clone, + R: Variant + Clone, + const X: bool, >( &mut self, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C, (), true> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X, (), true> + SendSync + 'static, ) -> &mut Self { self.register_indexer_set(set_fn) } @@ -550,7 +551,7 @@ impl Position { } #[allow(deprecated)] -impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { +impl TypeBuilder<'_, '_, T> { /// Register a custom fallible function. /// /// # Deprecated @@ -561,15 +562,15 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { /// This method will be removed in the next major version. #[deprecated(since = "1.9.1", note = "use `with_fn` instead")] #[inline(always)] - pub fn with_result_fn( + pub fn with_result_fn( &mut self, name: S, - method: F, + method: FUNC, ) -> &mut Self where S: AsRef + Into, R: Variant + Clone, - F: RegisterNativeFunction + SendSync + 'static, + FUNC: RhaiNativeFunc + SendSync + 'static, { self.with_fn(name, method) } @@ -589,10 +590,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { #[deprecated(since = "1.9.1", note = "use `with_get` instead")] #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn with_get_result( + pub fn with_get_result( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C, V, true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, true> + SendSync + 'static, ) -> &mut Self { self.with_get(name, get_fn) } @@ -610,10 +611,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { #[deprecated(since = "1.9.1", note = "use `with_set` instead")] #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn with_set_result( + pub fn with_set_result( &mut self, name: impl AsRef, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C, (), true> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, R), 2, X, (), true> + SendSync + 'static, ) -> &mut Self { self.with_set(name, set_fn) } @@ -633,9 +634,9 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { #[deprecated(since = "1.9.1", note = "use `with_indexer_get` instead")] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] - pub fn with_indexer_get_result( + pub fn with_indexer_get_result( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C, V, true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X, R, true> + SendSync + 'static, ) -> &mut Self { self.with_indexer_get(get_fn) } @@ -653,9 +654,9 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> { #[deprecated(since = "1.9.1", note = "use `with_indexer_set` instead")] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] - pub fn with_indexer_set_result( + pub fn with_indexer_set_result( &mut self, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C, (), true> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X, (), true> + SendSync + 'static, ) -> &mut Self { self.with_indexer_set(set_fn) } @@ -694,6 +695,99 @@ impl Module { pub fn get_custom_type(&self, type_name: &str) -> Option<&str> { self.get_custom_type_display_by_name(type_name) } + + /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key. + /// + /// If there is an existing Rust function of the same hash, it is replaced. + /// + /// # Deprecated + /// + /// This method is deprecated. + /// Use the [`FuncRegistration`] API instead. + /// + /// This method will be removed in the next major version. + #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")] + #[inline(always)] + pub fn set_fn( + &mut self, + name: impl Into, + namespace: FnNamespace, + _access: FnAccess, + arg_names: Option<&[&str]>, + arg_types: impl AsRef<[TypeId]>, + func: RhaiFunc, + ) -> u64 { + let _arg_names = arg_names; + + let fx = FuncRegistration::new(name).with_namespace(namespace); + + #[cfg(feature = "metadata")] + let fx = if let Some(arg_names) = _arg_names { + fx.with_params_info(arg_names) + } else { + fx + }; + + fx.set_into_module_raw(self, arg_types, func).hash + } + + /// _(metadata)_ Set a native Rust function into the [`Module`], returning a [`u64`] hash key. + /// Exported under the `metadata` feature only. + /// + /// If there is an existing Rust function of the same hash, it is replaced. + /// + /// # Deprecated + /// + /// This method is deprecated. + /// Use the [`FuncRegistration`] API instead. + /// + /// This method will be removed in the next major version. + #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")] + #[cfg(feature = "metadata")] + #[inline(always)] + pub fn set_fn_with_comments>( + &mut self, + name: impl Into, + namespace: FnNamespace, + _access: FnAccess, + arg_names: Option<&[&str]>, + arg_types: impl AsRef<[TypeId]>, + comments: impl IntoIterator, + func: RhaiFunc, + ) -> u64 { + FuncRegistration::new(name) + .with_namespace(namespace) + .with_params_info(arg_names.unwrap_or(&[])) + .with_comments(comments) + .set_into_module_raw(self, arg_types, func) + .hash + } + + /// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function. + /// Exported under the `metadata` feature only. + /// + /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. + /// + /// # Deprecated + /// + /// This method is deprecated. + /// Use [`update_fn_metadata_with_comments`][`Module::update_fn_metadata_with_comments`] instead. + /// + /// This method will be removed in the next major version. + #[deprecated( + since = "1.17.0", + note = "use `update_fn_metadata_with_comments` instead" + )] + #[cfg(feature = "metadata")] + #[inline(always)] + #[allow(deprecated)] + pub fn update_fn_metadata>( + &mut self, + hash_fn: u64, + arg_names: impl IntoIterator, + ) -> &mut Self { + self.update_fn_metadata_with_comments(hash_fn, arg_names, [""; 0]) + } } #[cfg(not(feature = "no_index"))] diff --git a/src/api/limits.rs b/src/api/limits.rs index e03c624b7..c561ba372 100644 --- a/src/api/limits.rs +++ b/src/api/limits.rs @@ -62,6 +62,13 @@ pub struct Limits { /// /// Set to zero to effectively disable creating variables. pub num_variables: usize, + /// Maximum number of scripted functions allowed. + /// + /// Set to zero to effectively disable defining any function. + /// + /// Not available under `no_function`. + #[cfg(not(feature = "no_function"))] + pub num_functions: usize, /// Maximum number of [modules][crate::Module] allowed to load. /// /// Set to zero to effectively disable loading any [module][crate::Module]. @@ -97,6 +104,8 @@ impl Limits { function_expr_depth: NonZeroUsize::new(default_limits::MAX_FUNCTION_EXPR_DEPTH), num_operations: None, num_variables: usize::MAX, + #[cfg(not(feature = "no_function"))] + num_functions: usize::MAX, #[cfg(not(feature = "no_module"))] num_modules: usize::MAX, string_len: None, @@ -151,13 +160,11 @@ impl Engine { /// The maximum levels of function calls allowed for a script. /// /// Not available under `unchecked` or `no_function`. + #[cfg(not(feature = "no_function"))] #[inline(always)] #[must_use] pub const fn max_call_levels(&self) -> usize { - #[cfg(not(feature = "no_function"))] - return self.limits.call_stack_depth; - #[cfg(feature = "no_function")] - return 0; + self.limits.call_stack_depth } /// Set the maximum number of operations allowed for a script to run to avoid /// consuming too much resources (0 for unlimited). @@ -179,15 +186,15 @@ impl Engine { None => 0, } } - /// Set the maximum number of imported variables allowed for a script at any instant. + /// Set the maximum number of variables allowed for a script at any instant. /// /// Not available under `unchecked`. #[inline(always)] - pub fn set_max_variables(&mut self, modules: usize) -> &mut Self { - self.limits.num_variables = modules; + pub fn set_max_variables(&mut self, variables: usize) -> &mut Self { + self.limits.num_variables = variables; self } - /// The maximum number of imported variables allowed for a script at any instant. + /// The maximum number of variables allowed for a script at any instant. /// /// Not available under `unchecked`. #[inline(always)] @@ -195,6 +202,24 @@ impl Engine { pub const fn max_variables(&self) -> usize { self.limits.num_variables } + /// Set the maximum number of scripted functions allowed for a script at any instant. + /// + /// Not available under `unchecked` or `no_function` + #[cfg(not(feature = "no_function"))] + #[inline(always)] + pub fn set_max_functions(&mut self, functions: usize) -> &mut Self { + self.limits.num_functions = functions; + self + } + /// The maximum number of scripted functions allowed for a script at any instant. + /// + /// Not available under `unchecked` or `no_function` + #[cfg(not(feature = "no_function"))] + #[inline(always)] + #[must_use] + pub const fn max_functions(&self) -> usize { + self.limits.num_functions + } /// Set the maximum number of imported [modules][crate::Module] allowed for a script. /// /// Not available under `unchecked` or `no_module`. @@ -207,13 +232,11 @@ impl Engine { /// The maximum number of imported [modules][crate::Module] allowed for a script. /// /// Not available under `unchecked` or `no_module`. + #[cfg(not(feature = "no_module"))] #[inline(always)] #[must_use] pub const fn max_modules(&self) -> usize { - #[cfg(not(feature = "no_module"))] - return self.limits.num_modules; - #[cfg(feature = "no_module")] - return 0; + self.limits.num_modules } /// Set the depth limits for expressions (0 for unlimited). /// diff --git a/src/api/optimize.rs b/src/api/optimize.rs index 28b4ac971..59db8c261 100644 --- a/src/api/optimize.rs +++ b/src/api/optimize.rs @@ -58,7 +58,7 @@ impl Engine { #[cfg(not(feature = "no_function"))] ast.shared_lib() .iter_fn() - .map(|f| f.func.get_script_fn_def().cloned().expect("`ScriptFnDef`")) + .map(|(f, _)| f.get_script_fn_def().cloned().expect("`ScriptFuncDef`")) .collect(), optimization_level, ); diff --git a/src/api/register.rs b/src/api/register.rs index 794905a8e..9b25c0b39 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -1,10 +1,10 @@ //! Module that defines the public function/module registration API of [`Engine`]. -use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync}; -use crate::module::ModuleFlags; +use crate::func::{FnCallArgs, RhaiFunc, RhaiNativeFunc, SendSync}; +use crate::module::{FuncRegistration, ModuleFlags}; use crate::types::dynamic::Variant; use crate::{ - Engine, FnAccess, FnNamespace, Identifier, Module, NativeCallContext, RhaiResultOf, Shared, + Dynamic, Engine, FnNamespace, Identifier, Module, NativeCallContext, RhaiResultOf, Shared, SharedModule, }; use std::any::{type_name, TypeId}; @@ -64,26 +64,26 @@ impl Engine { pub fn register_fn< A: 'static, const N: usize, - const C: bool, + const X: bool, R: Variant + Clone, - const L: bool, - F: RegisterNativeFunction + SendSync + 'static, + const F: bool, + FUNC: RhaiNativeFunc + SendSync + 'static, >( &mut self, name: impl AsRef + Into, - func: F, + func: FUNC, ) -> &mut Self { - let param_types = F::param_types(); + let param_types = FUNC::param_types(); #[cfg(feature = "metadata")] - let mut param_type_names = F::param_names() + let mut param_type_names = FUNC::param_names() .iter() .map(|ty| format!("_: {}", self.format_type_name(ty))) .collect::>(); #[cfg(feature = "metadata")] - if F::return_type() != TypeId::of::<()>() { - param_type_names.push(self.format_type_name(F::return_type_name()).into()); + if FUNC::return_type() != TypeId::of::<()>() { + param_type_names.push(self.format_type_name(FUNC::return_type_name()).into()); } #[cfg(feature = "metadata")] @@ -91,31 +91,27 @@ impl Engine { .iter() .map(String::as_str) .collect::>(); - #[cfg(feature = "metadata")] - let param_type_names = Some(param_type_names.as_ref()); - - #[cfg(not(feature = "metadata"))] - let param_type_names: Option<&[&str]> = None; - let fn_name = name.as_ref(); + let fn_name = name.into(); let is_pure = true; #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - let is_pure = is_pure && (F::num_params() != 3 || fn_name != crate::engine::FN_IDX_SET); + let is_pure = is_pure && (FUNC::num_params() != 3 || fn_name != crate::engine::FN_IDX_SET); #[cfg(not(feature = "no_object"))] let is_pure = - is_pure && (F::num_params() != 2 || !fn_name.starts_with(crate::engine::FN_SET)); + is_pure && (FUNC::num_params() != 2 || !fn_name.starts_with(crate::engine::FN_SET)); + + let f = FuncRegistration::new(fn_name).with_namespace(FnNamespace::Global); - let func = func.into_callable_function(fn_name.into(), is_pure, true); + #[cfg(feature = "metadata")] + let f = f.with_params_info(param_type_names); - self.global_namespace_mut().set_fn( - name, - FnNamespace::Global, - FnAccess::Public, - param_type_names, + f.set_into_module_raw( + self.global_namespace_mut(), param_types, - func, + func.into_callable_function(is_pure, true), ); + self } /// Register a function of the [`Engine`]. @@ -143,13 +139,23 @@ impl Engine { arg_types: impl AsRef<[TypeId]>, func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf + SendSync + 'static, ) -> &mut Self { - self.global_namespace_mut().set_raw_fn( - name, - FnNamespace::Global, - FnAccess::Public, - arg_types, - func, - ); + FuncRegistration::new(name) + .with_namespace(FnNamespace::Global) + .set_into_module_raw( + self.global_namespace_mut(), + arg_types, + RhaiFunc::Method { + func: Shared::new( + move |ctx: Option, args: &mut FnCallArgs| { + func(ctx.unwrap(), args).map(Dynamic::from) + }, + ), + has_context: true, + is_pure: false, + is_volatile: true, + }, + ); + self } /// Register a custom type for use with the [`Engine`]. @@ -274,12 +280,12 @@ impl Engine { /// Register a fallible type iterator for an iterable type with the [`Engine`]. /// This is an advanced API. #[inline(always)] - pub fn register_iterator_result(&mut self) -> &mut Self + pub fn register_iterator_result(&mut self) -> &mut Self where - T: Variant + Clone + IntoIterator>, - X: Variant + Clone, + T: Variant + Clone + IntoIterator>, + R: Variant + Clone, { - self.global_namespace_mut().set_iterable_result::(); + self.global_namespace_mut().set_iterable_result::(); self } /// Register a getter function for a member of a registered type with the [`Engine`]. @@ -324,10 +330,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_get( + pub fn register_get( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C, V, L> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, F> + SendSync + 'static, ) -> &mut Self { self.register_fn(crate::engine::make_getter(name.as_ref()), get_fn) } @@ -374,10 +380,10 @@ impl Engine { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn register_set( + pub fn register_set( &mut self, name: impl AsRef, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C, (), L> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, R), 2, X, (), F> + SendSync + 'static, ) -> &mut Self { self.register_fn(crate::engine::make_setter(name.as_ref()), set_fn) } @@ -430,16 +436,16 @@ impl Engine { #[inline(always)] pub fn register_get_set< T: Variant + Clone, - const C1: bool, - const C2: bool, - V: Variant + Clone, - const L1: bool, - const L2: bool, + const X1: bool, + const X2: bool, + R: Variant + Clone, + const F1: bool, + const F2: bool, >( &mut self, name: impl AsRef, - get_fn: impl RegisterNativeFunction<(Mut,), 1, C1, V, L1> + SendSync + 'static, - set_fn: impl RegisterNativeFunction<(Mut, V), 2, C2, (), L2> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut,), 1, X1, R, F1> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, R), 2, X2, (), F2> + SendSync + 'static, ) -> &mut Self { self.register_get(&name, get_fn).register_set(&name, set_fn) } @@ -496,13 +502,13 @@ impl Engine { #[inline] pub fn register_indexer_get< T: Variant + Clone, - X: Variant + Clone, - const C: bool, - V: Variant + Clone, - const L: bool, + IDX: Variant + Clone, + const X: bool, + R: Variant + Clone, + const F: bool, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C, V, L> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X, R, F> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] assert!( @@ -583,13 +589,13 @@ impl Engine { #[inline] pub fn register_indexer_set< T: Variant + Clone, - X: Variant + Clone, - const C: bool, - V: Variant + Clone, - const L: bool, + IDX: Variant + Clone, + const X: bool, + R: Variant + Clone, + const F: bool, >( &mut self, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C, (), L> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X, (), F> + SendSync + 'static, ) -> &mut Self { #[cfg(not(feature = "no_index"))] assert!( @@ -671,16 +677,16 @@ impl Engine { #[inline(always)] pub fn register_indexer_get_set< T: Variant + Clone, - X: Variant + Clone, - const C1: bool, - const C2: bool, - V: Variant + Clone, - const L1: bool, - const L2: bool, + IDX: Variant + Clone, + const X1: bool, + const X2: bool, + R: Variant + Clone, + const F1: bool, + const F2: bool, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, X), 2, C1, V, L1> + SendSync + 'static, - set_fn: impl RegisterNativeFunction<(Mut, X, V), 3, C2, (), L2> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, IDX), 2, X1, R, F1> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, IDX, R), 3, X2, (), F2> + SendSync + 'static, ) -> &mut Self { self.register_indexer_get(get_fn) .register_indexer_set(set_fn) diff --git a/src/ast/ast.rs b/src/ast/ast.rs index 681378838..9a2444970 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -11,6 +11,7 @@ use std::{ ops::{Add, AddAssign}, ptr, }; +use thin_vec::ThinVec; /// Compiled AST (abstract syntax tree) of a Rhai script. /// @@ -22,7 +23,7 @@ pub struct AST { /// Source of the [`AST`]. source: Option, /// Global statements. - body: Box<[Stmt]>, + body: ThinVec, /// Script-defined functions. #[cfg(not(feature = "no_function"))] lib: crate::SharedModule, @@ -79,10 +80,7 @@ impl AST { source: None, #[cfg(feature = "metadata")] doc: crate::SmartString::new_const(), - body: statements - .into_iter() - .collect::>() - .into_boxed_slice(), + body: statements.into_iter().collect(), #[cfg(not(feature = "no_function"))] lib: functions.into(), #[cfg(not(feature = "no_module"))] @@ -102,10 +100,7 @@ impl AST { source: None, #[cfg(feature = "metadata")] doc: crate::SmartString::new_const(), - body: statements - .into_iter() - .collect::>() - .into_boxed_slice(), + body: statements.into_iter().collect(), #[cfg(not(feature = "no_function"))] lib: functions.into(), #[cfg(not(feature = "no_module"))] @@ -210,7 +205,7 @@ impl AST { #[cfg(not(feature = "internals"))] #[inline(always)] #[must_use] - pub(crate) const fn statements(&self) -> &[Stmt] { + pub(crate) fn statements(&self) -> &[Stmt] { &self.body } /// _(internals)_ Get the statements. @@ -218,14 +213,14 @@ impl AST { #[cfg(feature = "internals")] #[inline(always)] #[must_use] - pub const fn statements(&self) -> &[Stmt] { + pub fn statements(&self) -> &[Stmt] { &self.body } /// Get the statements. #[inline(always)] #[must_use] #[allow(dead_code)] - pub(crate) fn statements_mut(&mut self) -> &mut Box<[Stmt]> { + pub(crate) fn statements_mut(&mut self) -> &mut ThinVec { &mut self.body } /// Does this [`AST`] contain script-defined functions? @@ -643,12 +638,7 @@ impl AST { match (self.body.as_ref(), other.body.as_ref()) { (_, []) => (), ([], _) => self.body = other.body, - (_, _) => { - let mut body = self.body.to_vec(); - let other = other.body.to_vec(); - body.extend(other); - self.body = body.into_boxed_slice(); - } + (_, _) => self.body.extend(other.body), } #[cfg(not(feature = "no_function"))] @@ -711,7 +701,7 @@ impl AST { #[cfg(feature = "internals")] #[cfg(not(feature = "no_function"))] #[inline] - pub fn iter_fn_def(&self) -> impl Iterator> { + pub fn iter_fn_def(&self) -> impl Iterator> { self.lib.iter_script_fn().map(|(.., fn_def)| fn_def) } /// Iterate through all function definitions. @@ -721,7 +711,7 @@ impl AST { #[cfg(not(feature = "no_function"))] #[allow(dead_code)] #[inline] - pub(crate) fn iter_fn_def(&self) -> impl Iterator> { + pub(crate) fn iter_fn_def(&self) -> impl Iterator> { self.lib.iter_script_fn().map(|(.., fn_def)| fn_def) } /// Iterate through all function definitions. @@ -985,3 +975,23 @@ impl ASTNode<'_> { } } } + +/// _(internals)_ Encapsulated AST environment. +/// Exported under the `internals` feature only. +/// +/// 1) functions defined within the same AST +/// 2) the stack of imported [modules][crate::Module] +/// 3) global constants +#[derive(Debug, Clone)] +pub struct EncapsulatedEnviron { + /// Functions defined within the same [`AST`][crate::AST]. + #[cfg(not(feature = "no_function"))] + pub lib: crate::SharedModule, + /// Imported [modules][crate::Module]. + #[cfg(not(feature = "no_module"))] + pub imports: thin_vec::ThinVec<(ImmutableString, crate::SharedModule)>, + /// Globally-defined constants. + #[cfg(not(feature = "no_module"))] + #[cfg(not(feature = "no_function"))] + pub constants: Option, +} diff --git a/src/ast/expr.rs b/src/ast/expr.rs index a1d121bbf..9964f0c83 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -5,8 +5,8 @@ use crate::engine::KEYWORD_FN_PTR; use crate::tokenizer::Token; use crate::types::dynamic::Union; use crate::{ - calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, SmartString, StaticVec, - INT, + calc_fn_hash, Dynamic, FnArgsVec, FnPtr, Identifier, ImmutableString, Position, SmartString, + StaticVec, INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -23,7 +23,7 @@ use thin_vec::ThinVec; /// _(internals)_ A binary expression. /// Exported under the `internals` feature only. -#[derive(Debug, Clone, Hash)] +#[derive(Debug, Clone, Hash, Default)] pub struct BinaryExpr { /// LHS expression. pub lhs: Expr, @@ -39,9 +39,9 @@ pub struct BinaryExpr { #[derive(Debug, Clone, Hash)] pub struct CustomExpr { /// List of keywords. - pub inputs: Box<[Expr]>, + pub inputs: FnArgsVec, /// List of tokens actually parsed. - pub tokens: Box<[ImmutableString]>, + pub tokens: FnArgsVec, /// State value. pub state: Dynamic, /// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement @@ -191,7 +191,7 @@ pub struct FnCallExpr { /// Pre-calculated hashes. pub hashes: FnCallHashes, /// List of function call argument expressions. - pub args: Box<[Expr]>, + pub args: FnArgsVec, /// Does this function call capture the parent scope? pub capture_parent_scope: bool, /// Is this function call a native operator? diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 48808693f..69a63d244 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -10,7 +10,7 @@ pub mod namespace_none; pub mod script_fn; pub mod stmt; -pub use ast::{ASTNode, AST}; +pub use ast::{ASTNode, EncapsulatedEnviron, AST}; #[cfg(not(feature = "no_custom_syntax"))] pub use expr::CustomExpr; pub use expr::{BinaryExpr, Expr, FnCallExpr, FnCallHashes}; @@ -21,13 +21,13 @@ pub use namespace::Namespace; #[cfg(feature = "no_module")] pub use namespace_none::Namespace; #[cfg(not(feature = "no_function"))] -pub use script_fn::{ScriptFnDef, ScriptFnMetadata}; +pub use script_fn::{ScriptFnMetadata, ScriptFuncDef}; pub use stmt::{ - CaseBlocksList, ConditionalExpr, FlowControl, OpAssignment, RangeCase, Stmt, StmtBlock, - StmtBlockContainer, SwitchCasesCollection, + CaseBlocksList, FlowControl, OpAssignment, RangeCase, Stmt, StmtBlock, StmtBlockContainer, + SwitchCasesCollection, }; /// _(internals)_ Placeholder for a script-defined function. /// Exported under the `internals` feature only. #[cfg(feature = "no_function")] -pub type ScriptFnDef = (); +pub type ScriptFuncDef = (); diff --git a/src/ast/script_fn.rs b/src/ast/script_fn.rs index 74f892476..bd5b2dcde 100644 --- a/src/ast/script_fn.rs +++ b/src/ast/script_fn.rs @@ -10,7 +10,7 @@ use std::{fmt, hash::Hash}; /// _(internals)_ A type containing information on a script-defined function. /// Exported under the `internals` feature only. #[derive(Debug, Clone)] -pub struct ScriptFnDef { +pub struct ScriptFuncDef { /// Function body. pub body: StmtBlock, /// Function name. @@ -37,10 +37,10 @@ pub struct ScriptFnDef { /// /// Each line in non-block doc-comments starts with `///`. #[cfg(feature = "metadata")] - pub comments: Box<[crate::SmartString]>, + pub comments: crate::StaticVec, } -impl fmt::Display for ScriptFnDef { +impl fmt::Display for ScriptFuncDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "no_object"))] let this_type = self @@ -148,9 +148,9 @@ impl fmt::Display for ScriptFnMetadata<'_> { } } -impl<'a> From<&'a ScriptFnDef> for ScriptFnMetadata<'a> { +impl<'a> From<&'a ScriptFuncDef> for ScriptFnMetadata<'a> { #[inline] - fn from(value: &'a ScriptFnDef) -> Self { + fn from(value: &'a ScriptFuncDef) -> Self { Self { name: &value.name, params: value.params.iter().map(ImmutableString::as_str).collect(), diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 358fe5554..c9eff5aa1 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -6,7 +6,7 @@ use crate::func::StraightHashMap; use crate::tokenizer::Token; use crate::types::dynamic::Union; use crate::types::Span; -use crate::{calc_fn_hash, Dynamic, Position, INT}; +use crate::{calc_fn_hash, Dynamic, FnArgsVec, Position, StaticVec, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -17,7 +17,6 @@ use std::{ num::NonZeroUsize, ops::{Range, RangeInclusive}, }; -use thin_vec::ThinVec; /// _(internals)_ An op-assignment operator. /// Exported under the `internals` feature only. @@ -180,53 +179,6 @@ impl fmt::Debug for OpAssignment { } } -/// _(internals)_ An expression with a condition. -/// Exported under the `internals` feature only. -/// -/// The condition may simply be [`Expr::BoolConstant`] with `true` if there is actually no condition. -#[derive(Debug, Clone, Default, Hash)] -pub struct ConditionalExpr { - /// Condition. - pub condition: Expr, - /// Expression. - pub expr: Expr, -} - -impl> From for ConditionalExpr { - #[inline(always)] - fn from(value: E) -> Self { - Self { - condition: Expr::BoolConstant(true, Position::NONE), - expr: value.into(), - } - } -} - -impl> From<(Expr, E)> for ConditionalExpr { - #[inline(always)] - fn from(value: (Expr, E)) -> Self { - Self { - condition: value.0, - expr: value.1.into(), - } - } -} - -impl ConditionalExpr { - /// Is the condition always `true`? - #[inline(always)] - #[must_use] - pub const fn is_always_true(&self) -> bool { - matches!(self.condition, Expr::BoolConstant(true, ..)) - } - /// Is the condition always `false`? - #[inline(always)] - #[must_use] - pub const fn is_always_false(&self) -> bool { - matches!(self.condition, Expr::BoolConstant(false, ..)) - } -} - /// _(internals)_ A type containing a range case for a `switch` statement. /// Exported under the `internals` feature only. #[derive(Clone, Hash)] @@ -379,12 +331,12 @@ pub type CaseBlocksList = smallvec::SmallVec<[usize; 2]>; /// Exported under the `internals` feature only. #[derive(Debug, Clone)] pub struct SwitchCasesCollection { - /// List of [`ConditionalExpr`]'s. - pub expressions: ThinVec, + /// List of conditional expressions: LHS = condition, RHS = expression. + pub expressions: FnArgsVec, /// Dictionary mapping value hashes to [`ConditionalExpr`]'s. pub cases: StraightHashMap, /// List of range cases. - pub ranges: ThinVec, + pub ranges: StaticVec, /// Statements block for the default case (there can be no condition for the default case). pub def_case: Option, } @@ -902,14 +854,14 @@ impl Stmt { expr.is_pure() && sw.cases.values().flat_map(|cases| cases.iter()).all(|&c| { let block = &sw.expressions[c]; - block.condition.is_pure() && block.expr.is_pure() + block.lhs.is_pure() && block.rhs.is_pure() }) && sw.ranges.iter().all(|r| { let block = &sw.expressions[r.index()]; - block.condition.is_pure() && block.expr.is_pure() + block.lhs.is_pure() && block.rhs.is_pure() }) && sw.def_case.is_some() - && sw.expressions[sw.def_case.unwrap()].expr.is_pure() + && sw.expressions[sw.def_case.unwrap()].rhs.is_pure() } // Loops that exit can be pure because it can never be infinite. @@ -1059,10 +1011,10 @@ impl Stmt { for &b in blocks { let block = &sw.expressions[b]; - if !block.condition.walk(path, on_node) { + if !block.lhs.walk(path, on_node) { return false; } - if !block.expr.walk(path, on_node) { + if !block.rhs.walk(path, on_node) { return false; } } @@ -1070,15 +1022,15 @@ impl Stmt { for r in &sw.ranges { let block = &sw.expressions[r.index()]; - if !block.condition.walk(path, on_node) { + if !block.lhs.walk(path, on_node) { return false; } - if !block.expr.walk(path, on_node) { + if !block.rhs.walk(path, on_node) { return false; } } if let Some(index) = sw.def_case { - if !sw.expressions[index].expr.walk(path, on_node) { + if !sw.expressions[index].lhs.walk(path, on_node) { return false; } } diff --git a/src/engine.rs b/src/engine.rs index 91278e2e7..d974d4aec 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -314,25 +314,11 @@ impl Engine { } /// Get an interned [string][ImmutableString]. - #[cfg(not(feature = "internals"))] - #[inline(always)] - #[must_use] - pub(crate) fn get_interned_string( - &self, - string: impl AsRef + Into, - ) -> ImmutableString { - match self.interned_strings { - Some(ref interner) => locked_write(interner).get(string), - _ => string.into(), - } - } - - /// _(internals)_ Get an interned [string][ImmutableString]. - /// Exported under the `internals` feature only. /// /// [`Engine`] keeps a cache of [`ImmutableString`] instances and tries to avoid new allocations - /// when an existing instance is found. - #[cfg(feature = "internals")] + /// and save memory when an existing instance is found. + /// + /// It is usually a good idea to intern strings if they are used frequently. #[inline] #[must_use] pub fn get_interned_string( diff --git a/src/eval/cache.rs b/src/eval/cache.rs index 25302de4a..8feedb05a 100644 --- a/src/eval/cache.rs +++ b/src/eval/cache.rs @@ -1,6 +1,6 @@ //! System caches. -use crate::func::{CallableFunction, StraightHashMap}; +use crate::func::{RhaiFunc, StraightHashMap}; use crate::types::BloomFilterU64; use crate::{ImmutableString, StaticVec}; #[cfg(feature = "no_std")] @@ -11,7 +11,7 @@ use std::prelude::v1::*; #[derive(Debug, Clone)] pub struct FnResolutionCacheEntry { /// Function. - pub func: CallableFunction, + pub func: RhaiFunc, /// Optional source. pub source: Option, } diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index fb2a576eb..f6c6e7ba4 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -253,7 +253,7 @@ pub struct Debugger { /// The current set of break-points. break_points: Vec, /// The current function call stack. - call_stack: ThinVec, + call_stack: Vec, /// The current state. state: Dynamic, } @@ -266,7 +266,7 @@ impl Debugger { Self { status, break_points: Vec::new(), - call_stack: ThinVec::new(), + call_stack: Vec::new(), state: Dynamic::UNIT, } } diff --git a/src/eval/expr.rs b/src/eval/expr.rs index dcb175cf4..9e9468f3b 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -73,7 +73,7 @@ pub fn search_scope_only<'s>( { let val: Dynamic = crate::FnPtr { name: v.3.clone(), - curry: thin_vec::ThinVec::new(), + curry: <_>::default(), environ: None, fn_def: Some(fn_def.clone()), } diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index 501348e6b..3990d84cb 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -224,7 +224,7 @@ impl GlobalRuntimeState { &self, hash: u64, global_namespace_only: bool, - ) -> Option<(&crate::func::CallableFunction, Option<&ImmutableString>)> { + ) -> Option<(&crate::func::RhaiFunc, Option<&ImmutableString>)> { if global_namespace_only { self.modules .iter() @@ -256,7 +256,7 @@ impl GlobalRuntimeState { #[cfg(not(feature = "no_module"))] #[inline] #[must_use] - pub fn get_iter(&self, id: std::any::TypeId) -> Option<&crate::func::IteratorFn> { + pub fn get_iter(&self, id: std::any::TypeId) -> Option<&crate::func::FnIterator> { self.modules .iter() .rev() diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 476301b38..de82c5200 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -15,11 +15,15 @@ pub use cache::{Caches, FnResolutionCacheEntry}; #[cfg(not(feature = "no_index"))] pub use data_check::calc_array_sizes; #[cfg(not(feature = "unchecked"))] +#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] pub use data_check::calc_data_sizes; #[cfg(feature = "debugging")] +#[cfg(not(feature = "no_function"))] +pub use debugger::CallStackFrame; +#[cfg(feature = "debugging")] pub use debugger::{ - BreakPoint, CallStackFrame, Debugger, DebuggerCommand, DebuggerEvent, DebuggerStatus, - OnDebuggerCallback, OnDebuggingInit, + BreakPoint, Debugger, DebuggerCommand, DebuggerEvent, DebuggerStatus, OnDebuggerCallback, + OnDebuggingInit, }; pub use eval_context::EvalContext; #[cfg(not(feature = "no_module"))] diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 540aaf5df..ca2e06798 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -2,8 +2,7 @@ use super::{Caches, EvalContext, GlobalRuntimeState, Target}; use crate::ast::{ - ASTFlags, BinaryExpr, ConditionalExpr, Expr, FlowControl, OpAssignment, Stmt, - SwitchCasesCollection, + ASTFlags, BinaryExpr, Expr, FlowControl, OpAssignment, Stmt, SwitchCasesCollection, }; use crate::eval::search_namespace; use crate::func::{get_builtin_op_assignment_fn, get_hasher}; @@ -526,7 +525,7 @@ impl Engine { for &index in case_blocks_list { let block = &expressions[index]; - let cond_result = match block.condition { + let cond_result = match block.lhs { Expr::BoolConstant(b, ..) => b, ref c => self .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), c)? @@ -537,16 +536,16 @@ impl Engine { }; if cond_result { - result = Some(&block.expr); + result = Some(&block.rhs); break; } } } else if !ranges.is_empty() { // Then check integer ranges for r in ranges.iter().filter(|r| r.contains(&value)) { - let ConditionalExpr { condition, expr } = &expressions[r.index()]; + let BinaryExpr { lhs, rhs } = &expressions[r.index()]; - let cond_result = match condition { + let cond_result = match lhs { Expr::BoolConstant(b, ..) => *b, c => self .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), c)? @@ -557,7 +556,7 @@ impl Engine { }; if cond_result { - result = Some(expr); + result = Some(rhs); break; } } @@ -565,7 +564,7 @@ impl Engine { } result - .or_else(|| def_case.as_ref().map(|&index| &expressions[index].expr)) + .or_else(|| def_case.as_ref().map(|&index| &expressions[index].rhs)) .map_or(Ok(Dynamic::UNIT), |expr| { self.eval_expr(global, caches, scope, this_ptr, expr) }) diff --git a/src/func/call.rs b/src/func/call.rs index baa7a0ad0..1980e8096 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1,6 +1,6 @@ //! Implement function-calling mechanism for [`Engine`]. -use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn, CallableFunction}; +use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn, RhaiFunc}; use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS; use crate::ast::{Expr, FnCallExpr, FnCallHashes}; use crate::engine::{ @@ -277,7 +277,7 @@ impl Engine { get_builtin_op_assignment_fn(token, first_arg, rest_args[0]) .map(|(f, has_context)| FnResolutionCacheEntry { - func: CallableFunction::Method { + func: RhaiFunc::Method { func: Shared::new(f), has_context, is_pure: false, @@ -288,7 +288,7 @@ impl Engine { } Some(token) => get_builtin_binary_op_fn(token, args[0], args[1]) .map(|(f, has_context)| FnResolutionCacheEntry { - func: CallableFunction::Method { + func: RhaiFunc::Method { func: Shared::new(f), has_context, is_pure: true, @@ -407,10 +407,8 @@ impl Engine { f if !f.is_pure() && !args.is_empty() && args[0].is_read_only() => { Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into()) } - CallableFunction::Plugin { func } => func.call(context, args), - CallableFunction::Pure { func, .. } | CallableFunction::Method { func, .. } => { - func(context, args) - } + RhaiFunc::Plugin { func } => func.call(context, args), + RhaiFunc::Pure { func, .. } | RhaiFunc::Method { func, .. } => func(context, args), _ => unreachable!("non-native function"), } .and_then(|r| self.check_data_size(r, pos)) @@ -628,7 +626,7 @@ impl Engine { } if let Some(FnResolutionCacheEntry { func, source }) = resolved.cloned() { - let CallableFunction::Script { fn_def, environ } = func else { + let RhaiFunc::Script { fn_def, environ } = func else { unreachable!("Script function expected"); }; @@ -1529,7 +1527,7 @@ impl Engine { } // Clone first argument if the function is not a method after-all - if !func.map_or(true, CallableFunction::is_method) { + if !func.map_or(true, RhaiFunc::is_method) { if let Some(first) = first_arg_value { *first = args[0].clone(); args[0] = first; @@ -1540,7 +1538,7 @@ impl Engine { match func { #[cfg(not(feature = "no_function"))] - Some(CallableFunction::Script { fn_def, environ }) => { + Some(RhaiFunc::Script { fn_def, environ }) => { let environ = environ.as_deref(); let scope = &mut Scope::new(); @@ -1557,7 +1555,7 @@ impl Engine { Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into()) } - Some(CallableFunction::Plugin { func }) => { + Some(RhaiFunc::Plugin { func }) => { let context = func .has_context() .then(|| (self, fn_name, module.id(), &*global, pos).into()); @@ -1566,10 +1564,10 @@ impl Engine { } Some( - CallableFunction::Pure { + RhaiFunc::Pure { func, has_context, .. } - | CallableFunction::Method { + | RhaiFunc::Method { func, has_context, .. }, ) => { @@ -1578,7 +1576,7 @@ impl Engine { func(context, args).and_then(|r| self.check_data_size(r, pos)) } - Some(CallableFunction::Iterator { .. }) => { + Some(RhaiFunc::Iterator { .. }) => { unreachable!("iterator functions should not occur here") } diff --git a/src/func/args.rs b/src/func/func_args.rs similarity index 100% rename from src/func/args.rs rename to src/func/func_args.rs diff --git a/src/func/func.rs b/src/func/func_trait.rs similarity index 100% rename from src/func/func.rs rename to src/func/func_trait.rs diff --git a/src/func/callable_function.rs b/src/func/function.rs similarity index 85% rename from src/func/callable_function.rs rename to src/func/function.rs index 61412348f..5587b9480 100644 --- a/src/func/callable_function.rs +++ b/src/func/function.rs @@ -1,38 +1,18 @@ //! Module defining the standard Rhai function type. -use super::native::{FnAny, FnPlugin, IteratorFn, SendSync}; -use crate::ast::FnAccess; -use crate::plugin::PluginFunction; +use super::native::{FnAny, FnIterator, FnPlugin, SendSync}; +use crate::ast::{EncapsulatedEnviron, FnAccess}; +use crate::plugin::PluginFunc; use crate::Shared; use std::fmt; #[cfg(feature = "no_std")] use std::prelude::v1::*; -/// _(internals)_ Encapsulated AST environment. -/// Exported under the `internals` feature only. -/// -/// 1) functions defined within the same AST -/// 2) the stack of imported [modules][crate::Module] -/// 3) global constants -#[derive(Debug, Clone)] -pub struct EncapsulatedEnviron { - /// Functions defined within the same [`AST`][crate::AST]. - #[cfg(not(feature = "no_function"))] - pub lib: crate::SharedModule, - /// Imported [modules][crate::Module]. - #[cfg(not(feature = "no_module"))] - pub imports: thin_vec::ThinVec<(crate::ImmutableString, crate::SharedModule)>, - /// Globally-defined constants. - #[cfg(not(feature = "no_module"))] - #[cfg(not(feature = "no_function"))] - pub constants: Option, -} - /// _(internals)_ A type encapsulating a function callable by Rhai. /// Exported under the `internals` feature only. #[derive(Clone)] #[non_exhaustive] -pub enum CallableFunction { +pub enum RhaiFunc { /// A pure native Rust function with all arguments passed by value. Pure { /// Shared function pointer. @@ -63,7 +43,7 @@ pub enum CallableFunction { /// An iterator function. Iterator { /// Shared function pointer. - func: Shared, + func: Shared, }, /// A plugin function, Plugin { @@ -73,14 +53,14 @@ pub enum CallableFunction { /// A script-defined function. #[cfg(not(feature = "no_function"))] Script { - /// Shared reference to the [`ScriptFnDef`][crate::ast::ScriptFnDef] function definition. - fn_def: Shared, + /// Shared reference to the [`ScriptFuncDef`][crate::ast::ScriptFuncDef] function definition. + fn_def: Shared, /// Encapsulated environment, if any. environ: Option>, }, } -impl fmt::Debug for CallableFunction { +impl fmt::Debug for RhaiFunc { #[cold] #[inline(never)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -96,7 +76,7 @@ impl fmt::Debug for CallableFunction { } } -impl fmt::Display for CallableFunction { +impl fmt::Display for RhaiFunc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Pure { .. } => f.write_str("NativePureFunction"), @@ -110,7 +90,7 @@ impl fmt::Display for CallableFunction { } } -impl CallableFunction { +impl RhaiFunc { /// Is this a pure native Rust function? #[inline] #[must_use] @@ -260,7 +240,7 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] #[inline] #[must_use] - pub const fn get_script_fn_def(&self) -> Option<&Shared> { + pub const fn get_script_fn_def(&self) -> Option<&Shared> { match self { Self::Pure { .. } | Self::Method { .. } @@ -288,7 +268,7 @@ impl CallableFunction { /// Get a reference to an iterator function. #[inline] #[must_use] - pub fn get_iter_fn(&self) -> Option<&IteratorFn> { + pub fn get_iter_fn(&self) -> Option<&FnIterator> { match self { Self::Iterator { func, .. } => Some(&**func), Self::Pure { .. } | Self::Method { .. } | Self::Plugin { .. } => None, @@ -312,9 +292,9 @@ impl CallableFunction { } #[cfg(not(feature = "no_function"))] -impl From for CallableFunction { +impl From for RhaiFunc { #[inline(always)] - fn from(fn_def: crate::ast::ScriptFnDef) -> Self { + fn from(fn_def: crate::ast::ScriptFuncDef) -> Self { Self::Script { fn_def: fn_def.into(), environ: None, @@ -323,9 +303,9 @@ impl From for CallableFunction { } #[cfg(not(feature = "no_function"))] -impl From> for CallableFunction { +impl From> for RhaiFunc { #[inline(always)] - fn from(fn_def: Shared) -> Self { + fn from(fn_def: Shared) -> Self { Self::Script { fn_def, environ: None, @@ -333,7 +313,7 @@ impl From> for CallableFunction { } } -impl From for CallableFunction { +impl From for RhaiFunc { #[inline(always)] fn from(func: T) -> Self { Self::Plugin { @@ -342,7 +322,7 @@ impl From for CallableFunction { } } -impl From> for CallableFunction { +impl From> for RhaiFunc { #[inline(always)] fn from(func: Shared) -> Self { Self::Plugin { func } diff --git a/src/func/mod.rs b/src/func/mod.rs index 61471a53f..f8ed25dd0 100644 --- a/src/func/mod.rs +++ b/src/func/mod.rs @@ -1,27 +1,27 @@ //! Module defining mechanisms to handle function calls in Rhai. -pub mod args; pub mod builtin; pub mod call; -pub mod callable_function; +pub mod func_args; #[allow(clippy::module_inception)] -pub mod func; +pub mod func_trait; +pub mod function; pub mod hashing; pub mod native; pub mod plugin; pub mod register; pub mod script; -pub use args::FuncArgs; pub use builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn}; #[cfg(not(feature = "no_closure"))] pub use call::ensure_no_data_race; #[cfg(not(feature = "no_function"))] pub use call::is_anonymous_fn; pub use call::FnCallArgs; -pub use callable_function::{CallableFunction, EncapsulatedEnviron}; +pub use func_args::FuncArgs; #[cfg(not(feature = "no_function"))] -pub use func::Func; +pub use func_trait::Func; +pub use function::RhaiFunc; #[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_function"))] pub use hashing::calc_typed_method_hash; @@ -29,8 +29,9 @@ pub use hashing::{calc_fn_hash, calc_fn_hash_full, calc_var_hash, get_hasher, St #[cfg(feature = "internals")] #[allow(deprecated)] pub use native::NativeCallContextStore; +#[allow(unused_imports)] pub use native::{ locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone, - shared_try_take, IteratorFn, Locked, NativeCallContext, SendSync, Shared, + FnIterator, Locked, NativeCallContext, SendSync, Shared, }; -pub use register::RegisterNativeFunction; +pub use register::RhaiNativeFunc; diff --git a/src/func/native.rs b/src/func/native.rs index 4548773b5..f527537f3 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -3,7 +3,7 @@ use super::call::FnCallArgs; use crate::ast::FnCallHashes; use crate::eval::{Caches, GlobalRuntimeState}; -use crate::plugin::PluginFunction; +use crate::plugin::PluginFunc; use crate::tokenizer::{is_valid_function_name, Token, TokenizeState}; use crate::types::dynamic::Variant; use crate::{ @@ -568,18 +568,18 @@ pub type FnBuiltin = ( /// Function that gets an iterator from a type. #[cfg(not(feature = "sync"))] -pub type IteratorFn = dyn Fn(Dynamic) -> Box>>; +pub type FnIterator = dyn Fn(Dynamic) -> Box>>; /// Function that gets an iterator from a type. #[cfg(feature = "sync")] -pub type IteratorFn = +pub type FnIterator = dyn Fn(Dynamic) -> Box>> + Send + Sync; /// Plugin function trait object. #[cfg(not(feature = "sync"))] -pub type FnPlugin = dyn PluginFunction; +pub type FnPlugin = dyn PluginFunc; /// Plugin function trait object. #[cfg(feature = "sync")] -pub type FnPlugin = dyn PluginFunction + Send + Sync; +pub type FnPlugin = dyn PluginFunc + Send + Sync; /// Callback function for progress reporting. #[cfg(not(feature = "unchecked"))] diff --git a/src/func/plugin.rs b/src/func/plugin.rs index 2c8427718..9ca1889cd 100644 --- a/src/func/plugin.rs +++ b/src/func/plugin.rs @@ -1,10 +1,10 @@ //! Module defining macros for developing _plugins_. -pub use super::CallableFunction; use super::FnCallArgs; +pub use super::RhaiFunc; pub use crate::{ - Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, - NativeCallContext, Position, + Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, FuncRegistration, ImmutableString, + Module, NativeCallContext, Position, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -20,7 +20,7 @@ pub use rhai_codegen::*; /// /// This trait should not be used directly. /// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead. -pub trait PluginFunction { +pub trait PluginFunc { /// Call the plugin function with the arguments provided. fn call(&self, context: Option, args: &mut FnCallArgs) -> RhaiResult; diff --git a/src/func/register.rs b/src/func/register.rs index 41c53f417..7f6024059 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -6,7 +6,7 @@ #![allow(unused_variables)] use super::call::FnCallArgs; -use super::callable_function::CallableFunction; +use super::function::RhaiFunc; use super::native::{SendSync, Shared}; use crate::types::dynamic::{DynamicWriteLock, Union, Variant}; use crate::{Dynamic, Identifier, NativeCallContext, RhaiResultOf}; @@ -25,13 +25,13 @@ use std::{ /// /// # Examples /// -/// `RegisterNativeFunction<(Mut, B, Ref), 3, false, R, false>` = `Fn(&mut A, B, &C) -> R` +/// `RhaiNativeFunc<(Mut, B, Ref), 3, false, R, false>` = `Fn(&mut A, B, &C) -> R` /// -/// `RegisterNativeFunction<(Mut, B, Ref), 3, true, R, false>` = `Fn(NativeCallContext, &mut A, B, &C) -> R` +/// `RhaiNativeFunc<(Mut, B, Ref), 3, true, R, false>` = `Fn(NativeCallContext, &mut A, B, &C) -> R` /// -/// `RegisterNativeFunction<(Mut, B, Ref), 3, false, R, true>` = `Fn(&mut A, B, &C) -> Result>` +/// `RhaiNativeFunc<(Mut, B, Ref), 3, false, R, true>` = `Fn(&mut A, B, &C) -> Result>` /// -/// `RegisterNativeFunction<(Mut, B, Ref), 3, true, R, true>` = `Fn(NativeCallContext, &mut A, B, &C) -> Result>` +/// `RhaiNativeFunc<(Mut, B, Ref), 3, true, R, true>` = `Fn(NativeCallContext, &mut A, B, &C) -> Result>` /// /// These types are not actually used anywhere. pub struct Mut(T); @@ -78,22 +78,10 @@ pub fn by_value(data: &mut Dynamic) -> T { /// * `X` - a constant boolean generic indicating whether there is a `NativeCallContext` parameter. /// * `R` - return type of the function; if the function returns `Result`, it is the unwrapped inner value type. /// * `F` - a constant boolean generic indicating whether the function is fallible (i.e. returns `Result>`). -pub trait RegisterNativeFunction< - A: 'static, - const N: usize, - const X: bool, - R: 'static, - const F: bool, -> -{ - /// Convert this function into a [`CallableFunction`]. +pub trait RhaiNativeFunc { + /// Convert this function into a [`RhaiFunc`]. #[must_use] - fn into_callable_function( - self, - name: Identifier, - is_pure: bool, - is_volatile: bool, - ) -> CallableFunction; + fn into_callable_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc; /// Get the type ID's of this function's parameters. #[must_use] fn param_types() -> [TypeId; N]; @@ -153,11 +141,11 @@ macro_rules! def_register { FN: Fn($($param),*) -> RET + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone, - > RegisterNativeFunction<($($mark,)*), $n, false, RET, false> for FN { + > RhaiNativeFunc<($($mark,)*), $n, false, RET, false> for FN { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } - #[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool, is_volatile: bool) -> CallableFunction { - CallableFunction::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { + #[inline(always)] fn into_callable_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc { + RhaiFunc::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! let mut drain = args.iter_mut(); $(let mut $par = $clone(drain.next().unwrap()); )* @@ -175,11 +163,11 @@ macro_rules! def_register { FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RET + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone, - > RegisterNativeFunction<($($mark,)*), $n, true, RET, false> for FN { + > RhaiNativeFunc<($($mark,)*), $n, true, RET, false> for FN { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } - #[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool, is_volatile: bool) -> CallableFunction { - CallableFunction::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { + #[inline(always)] fn into_callable_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc { + RhaiFunc::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { let ctx = ctx.unwrap(); // The arguments are assumed to be of the correct number and types! @@ -199,12 +187,12 @@ macro_rules! def_register { FN: Fn($($param),*) -> RhaiResultOf + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<($($mark,)*), $n, false, RET, true> for FN { + > RhaiNativeFunc<($($mark,)*), $n, false, RET, true> for FN { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::>() } - #[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool, is_volatile: bool) -> CallableFunction { - CallableFunction::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { + #[inline(always)] fn into_callable_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc { + RhaiFunc::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! let mut drain = args.iter_mut(); $(let mut $par = $clone(drain.next().unwrap()); )* @@ -219,12 +207,12 @@ macro_rules! def_register { FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResultOf + SendSync + 'static, $($par: Variant + Clone,)* RET: Variant + Clone - > RegisterNativeFunction<($($mark,)*), $n, true, RET, true> for FN { + > RhaiNativeFunc<($($mark,)*), $n, true, RET, true> for FN { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::>() } - #[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool, is_volatile: bool) -> CallableFunction { - CallableFunction::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { + #[inline(always)] fn into_callable_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc { + RhaiFunc::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { let ctx = ctx.unwrap(); // The arguments are assumed to be of the correct number and types! @@ -242,7 +230,7 @@ macro_rules! def_register { ($p0:ident:$n0:expr $(, $p:ident: $n:expr)*) => { def_register!(imp Pure : $n0 ; $p0 => $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => $p => by_value)*); def_register!(imp Method : $n0 ; $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => $p => by_value)*); - // ^ CallableFunction constructor + // ^ RhaiFunc constructor // ^ number of arguments ^ first parameter passed through // ^ others passed by value (by_value) diff --git a/src/func/script.rs b/src/func/script.rs index ed98d39c4..719593fd9 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -2,9 +2,8 @@ #![cfg(not(feature = "no_function"))] use super::call::FnCallArgs; -use crate::ast::ScriptFnDef; +use crate::ast::{EncapsulatedEnviron, ScriptFuncDef}; use crate::eval::{Caches, GlobalRuntimeState}; -use crate::func::EncapsulatedEnviron; use crate::{Dynamic, Engine, Position, RhaiResult, Scope, ERR}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -29,7 +28,7 @@ impl Engine { scope: &mut Scope, mut this_ptr: Option<&mut Dynamic>, _environ: Option<&EncapsulatedEnviron>, - fn_def: &ScriptFnDef, + fn_def: &ScriptFuncDef, args: &mut FnCallArgs, rewind_scope: bool, pos: Position, diff --git a/src/lib.rs b/src/lib.rs index 4f270ec68..44cbfb53d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,8 +242,8 @@ pub use eval::EvalContext; #[cfg(not(feature = "no_object"))] use func::calc_typed_method_hash; use func::{calc_fn_hash, calc_fn_hash_full, calc_var_hash}; -pub use func::{plugin, FuncArgs, NativeCallContext, RegisterNativeFunction}; -pub use module::{FnNamespace, Module}; +pub use func::{plugin, FuncArgs, NativeCallContext, RhaiNativeFunc}; +pub use module::{FnNamespace, FuncRegistration, Module}; pub use packages::string_basic::{FUNC_TO_DEBUG, FUNC_TO_STRING}; pub use rhai_codegen::*; #[cfg(not(feature = "no_time"))] @@ -359,8 +359,9 @@ pub use api::default_limits; #[cfg(feature = "internals")] pub use ast::{ - ASTFlags, ASTNode, BinaryExpr, ConditionalExpr, Expr, FlowControl, FnCallExpr, FnCallHashes, - Ident, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, SwitchCasesCollection, + ASTFlags, ASTNode, BinaryExpr, EncapsulatedEnviron, Expr, FlowControl, FnCallExpr, + FnCallHashes, Ident, OpAssignment, RangeCase, ScriptFuncDef, Stmt, StmtBlock, + SwitchCasesCollection, }; #[cfg(feature = "internals")] @@ -371,15 +372,12 @@ pub use ast::CustomExpr; #[cfg(not(feature = "no_module"))] pub use ast::Namespace; -#[cfg(feature = "internals")] -pub use func::EncapsulatedEnviron; - #[cfg(feature = "internals")] pub use eval::{Caches, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState}; #[cfg(feature = "internals")] #[allow(deprecated)] -pub use func::{locked_read, locked_write, CallableFunction, NativeCallContextStore}; +pub use func::{locked_read, locked_write, NativeCallContextStore, RhaiFunc}; #[cfg(feature = "internals")] #[cfg(feature = "metadata")] diff --git a/src/module/mod.rs b/src/module/mod.rs index bb39e004a..4a01c9e6e 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -4,13 +4,12 @@ use crate::api::formatting::format_type; use crate::ast::FnAccess; use crate::func::{ - shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction, - SendSync, StraightHashMap, + shared_take_or_clone, FnIterator, RhaiFunc, RhaiNativeFunc, SendSync, StraightHashMap, }; use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypeInfo, CustomTypesCollection}; use crate::{ - calc_fn_hash, calc_fn_hash_full, Dynamic, Identifier, ImmutableString, NativeCallContext, - RhaiResultOf, Shared, SharedModule, SmartString, + calc_fn_hash, calc_fn_hash_full, Dynamic, FnArgsVec, Identifier, ImmutableString, RhaiResultOf, + Shared, SharedModule, SmartString, }; use bitflags::bitflags; #[cfg(feature = "no_std")] @@ -71,9 +70,9 @@ impl FnNamespace { } /// A type containing the metadata of a single registered function. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[non_exhaustive] -pub struct FuncInfoMetadata { +pub struct FuncMetadata { /// Hash value. pub hash: u64, /// Function namespace. @@ -82,53 +81,40 @@ pub struct FuncInfoMetadata { pub access: FnAccess, /// Function name. pub name: Identifier, - #[cfg(not(feature = "no_object"))] - /// Type of `this` pointer, if any. - pub this_type: Option, /// Number of parameters. pub num_params: usize, /// Parameter types (if applicable). - pub param_types: Box<[TypeId]>, + pub param_types: FnArgsVec, /// Parameter names and types (if available). #[cfg(feature = "metadata")] - pub params_info: Box<[Identifier]>, + pub params_info: FnArgsVec, /// Return type name. #[cfg(feature = "metadata")] pub return_type: Identifier, /// Comments. #[cfg(feature = "metadata")] - pub comments: Box<[SmartString]>, -} - -/// A type containing a single registered function. -#[derive(Debug, Clone)] -pub struct FuncInfo { - /// Function instance. - pub func: CallableFunction, - /// Function metadata. - pub metadata: Box, + pub comments: crate::StaticVec, } -impl FuncInfo { +impl FuncMetadata { /// _(metadata)_ Generate a signature of the function. /// Exported under the `metadata` feature only. #[cfg(feature = "metadata")] #[must_use] pub fn gen_signature(&self) -> String { - let mut signature = format!("{}(", self.metadata.name); + let mut signature = format!("{}(", self.name); - let return_type = format_type(&self.metadata.return_type, true); + let return_type = format_type(&self.return_type, true); - if self.metadata.params_info.is_empty() { - for x in 0..self.metadata.num_params { + if self.params_info.is_empty() { + for x in 0..self.num_params { signature.push('_'); - if x < self.metadata.num_params - 1 { + if x < self.num_params - 1 { signature.push_str(", "); } } } else { let params = self - .metadata .params_info .iter() .map(|param| { @@ -148,7 +134,7 @@ impl FuncInfo { } signature.push(')'); - if !self.func.is_script() && !return_type.is_empty() { + if !return_type.is_empty() { signature.push_str(" -> "); signature.push_str(&return_type); } @@ -178,6 +164,162 @@ pub fn calc_native_fn_hash<'a>( ) } +/// Type for fine-tuned module function registration. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct FuncRegistration { + metadata: FuncMetadata, +} + +impl FuncRegistration { + /// Create a new [`FuncRegistration`]. + /// + /// ``` + /// # use rhai::{Module, FuncRegistration, FnNamespace}; + /// let mut module = Module::new(); + /// + /// fn inc(x: i64) -> i64 { x + 1 } + /// + /// let f = FuncRegistration::new("inc") + /// .with_namespace(FnNamespace::Global) + /// .set_into_module(&mut module, inc); + /// + /// let hash = f.hash; + /// + /// assert!(module.contains_fn(hash)); + /// ``` + pub fn new(name: impl Into) -> Self { + Self { + metadata: FuncMetadata { + hash: 0, + name: name.into(), + namespace: FnNamespace::Internal, + access: FnAccess::Public, + num_params: 0, + param_types: <_>::default(), + #[cfg(feature = "metadata")] + params_info: <_>::default(), + #[cfg(feature = "metadata")] + return_type: "".into(), + #[cfg(feature = "metadata")] + comments: <_>::default(), + }, + } + } + /// Set the [namespace][`FnNamespace`] of the function. + pub fn with_namespace(mut self, namespace: FnNamespace) -> Self { + self.metadata.namespace = namespace; + self + } + /// _(metadata)_ Set the function's parameter names and/or types. + /// Exported under the `metadata` feature only. + #[cfg(feature = "metadata")] + pub fn with_params_info>(mut self, params: impl IntoIterator) -> Self { + self.metadata.params_info = params.into_iter().map(|s| s.as_ref().into()).collect(); + self + } + /// _(metadata)_ Set the function's doc-comments. + /// Exported under the `metadata` feature only. + #[cfg(feature = "metadata")] + pub fn with_comments>(mut self, comments: impl IntoIterator) -> Self { + self.metadata.comments = comments.into_iter().map(|s| s.as_ref().into()).collect(); + self + } + /// Register the function into the specified [`Module`]. + /// + /// # Assumptions + /// + /// * The function is assumed to be _pure_ (so it can be called on constants) unless it is a property setter or an index setter. + /// + /// * The function is assumed to be _volatile_ -- i.e. it does not guarantee the same result for the same input(s). + #[inline] + pub fn set_into_module( + self, + module: &mut Module, + func: FUNC, + ) -> &FuncMetadata + where + R: Variant + Clone, + FUNC: RhaiNativeFunc + SendSync + 'static, + { + let is_pure = true; + + #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] + let is_pure = + is_pure && (FUNC::num_params() != 3 || self.metadata.name != crate::engine::FN_IDX_SET); + #[cfg(not(feature = "no_object"))] + let is_pure = is_pure + && (FUNC::num_params() != 2 || !self.metadata.name.starts_with(crate::engine::FN_SET)); + + let func = func.into_callable_function(is_pure, true); + self.set_into_module_raw(module, FUNC::param_types(), func) + } + /// Register the function into the specified [`Module`]. + #[inline] + pub fn set_into_module_raw( + self, + module: &mut Module, + arg_types: impl AsRef<[TypeId]>, + func: RhaiFunc, + ) -> &FuncMetadata { + let mut f = self.metadata; + + f.num_params = arg_types.as_ref().len(); + f.param_types.extend(arg_types.as_ref().iter().copied()); + + let is_method = func.is_method(); + + f.param_types + .iter_mut() + .enumerate() + .for_each(|(i, type_id)| *type_id = Module::map_type(!is_method || i > 0, *type_id)); + + let is_dynamic = f + .param_types + .iter() + .any(|&type_id| type_id == TypeId::of::()); + + #[cfg(feature = "metadata")] + if f.params_info.len() > f.param_types.len() { + f.return_type = f.params_info.pop().unwrap(); + } + + let hash_base = calc_fn_hash(None, &f.name, f.param_types.len()); + let hash_fn = calc_fn_hash_full(hash_base, f.param_types.iter().copied()); + f.hash = hash_fn; + + // Catch hash collisions in testing environment only. + #[cfg(feature = "testing-environ")] + if let Some(fx) = module.functions.as_ref().and_then(|f| f.get(&hash_base)) { + unreachable!( + "Hash {} already exists when registering function {}:\n{:#?}", + hash_base, f.name, fx + ); + } + + if is_dynamic { + module.dynamic_functions_filter.mark(hash_base); + } + + module + .flags + .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS); + + let entry = match module + .functions + .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE)) + .entry(hash_fn) + { + Entry::Occupied(mut entry) => { + entry.insert((func, f.into())); + entry.into_mut() + } + Entry::Vacant(entry) => entry.insert((func, f.into())), + }; + + &*entry.1 + } +} + bitflags! { /// Bit-flags containing all status for [`Module`]. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] @@ -211,16 +353,16 @@ pub struct Module { /// Flattened collection of all [`Module`] variables, including those in sub-modules. all_variables: Option>, /// Functions (both native Rust and scripted). - functions: Option>, + functions: Option)>>, /// Flattened collection of all functions, native Rust and scripted. /// including those in sub-modules. - all_functions: Option>, + all_functions: Option>, /// Bloom filter on native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters. dynamic_functions_filter: BloomFilterU64, /// Iterator functions, keyed by the type producing the iterator. - type_iterators: BTreeMap>, + type_iterators: BTreeMap>, /// Flattened collection of iterator functions, including those in sub-modules. - all_type_iterators: BTreeMap>, + all_type_iterators: BTreeMap>, /// Flags. pub(crate) flags: ModuleFlags, } @@ -257,7 +399,12 @@ impl fmt::Debug for Module { "functions", &self .iter_fn() - .map(|f| f.func.to_string()) + .map(|(_f, _m)| { + #[cfg(not(feature = "metadata"))] + return _f.to_string(); + #[cfg(feature = "metadata")] + return _m.gen_signature(); + }) .collect::>(), ) .field("flags", &self.flags); @@ -270,7 +417,7 @@ impl fmt::Debug for Module { } #[cfg(not(feature = "no_function"))] -impl>> From for Module { +impl>> From for Module { fn from(iter: T) -> Self { let mut module = Self::new(); iter.into_iter().for_each(|fn_def| { @@ -709,11 +856,12 @@ impl Module { #[inline] pub fn gen_fn_signatures(&self) -> impl Iterator + '_ { self.iter_fn() - .filter(|&f| match f.metadata.access { + .map(|(_, f)| f) + .filter(|&f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) - .map(FuncInfo::gen_signature) + .map(FuncMetadata::gen_signature) } /// Does a variable exist in the [`Module`]? @@ -821,7 +969,7 @@ impl Module { /// If there is an existing function of the same name and number of arguments, it is replaced. #[cfg(not(feature = "no_function"))] #[inline] - pub fn set_script_fn(&mut self, fn_def: impl Into>) -> u64 { + pub fn set_script_fn(&mut self, fn_def: impl Into>) -> u64 { let fn_def = fn_def.into(); // None + function name + number of arguments. @@ -849,34 +997,24 @@ impl Module { ); } - #[cfg(feature = "metadata")] - let params_info = fn_def.params.iter().map(Into::into).collect(); + let metadata = FuncMetadata { + hash: hash_script, + name: fn_def.name.as_str().into(), + namespace, + access: fn_def.access, + num_params, + param_types: FnArgsVec::new_const(), + #[cfg(feature = "metadata")] + params_info: fn_def.params.iter().map(Into::into).collect(), + #[cfg(feature = "metadata")] + return_type: <_>::default(), + #[cfg(feature = "metadata")] + comments: crate::StaticVec::new_const(), + }; self.functions .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE)) - .insert( - hash_script, - FuncInfo { - metadata: FuncInfoMetadata { - hash: hash_script, - name: fn_def.name.as_str().into(), - namespace, - access: fn_def.access, - #[cfg(not(feature = "no_object"))] - this_type: fn_def.this_type.clone(), - num_params, - param_types: <_>::default(), - #[cfg(feature = "metadata")] - params_info, - #[cfg(feature = "metadata")] - return_type: "".into(), - #[cfg(feature = "metadata")] - comments: <_>::default(), - } - .into(), - func: fn_def.into(), - }, - ); + .insert(hash_script, (fn_def.into(), metadata.into())); self.flags .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS); @@ -893,13 +1031,13 @@ impl Module { &self, name: impl AsRef, num_params: usize, - ) -> Option<&Shared> { + ) -> Option<&Shared> { self.functions.as_ref().and_then(|lib| { let name = name.as_ref(); lib.values() - .find(|&f| f.metadata.num_params == num_params && f.metadata.name == name) - .and_then(|f| f.func.get_script_fn_def()) + .find(|(_, f)| f.num_params == num_params && f.name == name) + .and_then(|(f, _)| f.get_script_fn_def()) }) } @@ -1004,93 +1142,61 @@ impl Module { .map_or(false, |m| m.contains_key(&hash_fn)) } - /// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function. + /// _(metadata)_ Update the metadata (parameter names/types, return type and doc-comments) of a registered function. /// Exported under the `metadata` feature only. /// /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. /// - /// ## Parameter Names and Types - /// - /// Each parameter name/type pair should be a single string of the format: `var_name: type`. + /// # Deprecated /// - /// ## Return Type + /// This method is deprecated. + /// Use the [`FuncRegistration`] API instead. /// - /// 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. + /// This method will be removed in the next major version. + #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")] #[cfg(feature = "metadata")] #[inline] - pub fn update_fn_metadata>( + pub fn update_fn_metadata_with_comments, C: Into>( &mut self, hash_fn: u64, - arg_names: impl IntoIterator, + arg_names: impl IntoIterator, + comments: impl IntoIterator, ) -> &mut Self { - let mut param_names = arg_names.into_iter().map(Into::into).collect::>(); - - if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { - let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params { - let return_type = param_names.pop().unwrap(); - (param_names, return_type) + let mut params_info = arg_names + .into_iter() + .map(Into::into) + .collect::>(); + + if let Some((_, f)) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { + let (params_info, return_type_name) = if params_info.len() > f.num_params { + let return_type = params_info.pop().unwrap(); + (params_info, return_type) } else { - (param_names, crate::SmartString::new_const()) + (params_info, crate::SmartString::new_const()) }; - f.metadata.params_info = param_names.into_boxed_slice(); - f.metadata.return_type = return_type_name; + f.params_info = params_info; + f.return_type = return_type_name; + f.comments = comments.into_iter().map(Into::into).collect(); } self } - /// _(metadata)_ Update the metadata (parameter names/types, return type and doc-comments) of a registered function. - /// Exported under the `metadata` feature only. + /// Update the namespace of a registered function. /// /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. /// - /// ## Parameter Names and Types - /// - /// Each parameter name/type pair should be a single string of the format: `var_name: type`. - /// - /// ## Return 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. - /// - /// ## Comments - /// - /// Block doc-comments should be kept in a separate string slice. - /// - /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break. - /// - /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding - /// doc-comment leader: `///` or `/**`. + /// # Deprecated /// - /// Each line in non-block doc-comments should start with `///`. - #[cfg(feature = "metadata")] - #[inline] - pub fn update_fn_metadata_with_comments, C: Into>( - &mut self, - hash_fn: u64, - arg_names: impl IntoIterator, - comments: impl IntoIterator, - ) -> &mut Self { - self.update_fn_metadata(hash_fn, arg_names); - - self.functions - .as_mut() - .and_then(|m| m.get_mut(&hash_fn)) - .unwrap() - .metadata - .comments = comments.into_iter().map(Into::into).collect(); - - self - } - - /// Update the namespace of a registered function. + /// This method is deprecated. + /// Use the [`FuncRegistration`] API instead. /// - /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. + /// This method will be removed in the next major version. + #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")] #[inline] pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { - if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { - f.metadata.namespace = namespace; + if let Some((_, f)) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { + f.namespace = namespace; self.flags .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS); } @@ -1116,278 +1222,15 @@ impl Module { type_id } - /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key. - /// - /// If there is an existing Rust function of the same hash, it is replaced. - /// - /// # WARNING - Low Level API - /// - /// This function is very low level. - /// - /// ## Parameter Names and Types - /// - /// Each parameter name/type pair should be a single string of the format: `var_name: type`. - /// - /// ## Return 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. + /// Set a native Rust function into the [`Module`] based on a [`FuncRegistration`]. #[inline(always)] - pub fn set_fn( + pub fn set_fn_raw_with_options( &mut self, - name: impl Into, - namespace: FnNamespace, - access: FnAccess, - arg_names: Option<&[&str]>, + options: FuncRegistration, arg_types: impl AsRef<[TypeId]>, - func: CallableFunction, - ) -> u64 { - const EMPTY: &[&str] = &[]; - let arg_names = arg_names.unwrap_or(EMPTY); - - self._set_fn(name, namespace, access, arg_names, arg_types, EMPTY, func) - .metadata - .hash - } - - /// _(metadata)_ Set a native Rust function into the [`Module`], returning a [`u64`] hash key. - /// Exported under the `metadata` feature only. - /// - /// If there is an existing Rust function of the same hash, it is replaced. - /// - /// # WARNING - Low Level API - /// - /// This function is very low level. - /// - /// ## Parameter Names and Types - /// - /// Each parameter name/type pair should be a single string of the format: `var_name: type`. - /// - /// ## Return 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. - /// - /// ## Comments - /// - /// Block doc-comments should be kept in a separate string slice. - /// - /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break. - /// - /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding - /// doc-comment leader: `///` or `/**`. - /// - /// Each line in non-block doc-comments should start with `///`. - #[cfg(feature = "metadata")] - #[inline(always)] - pub fn set_fn_with_comments>( - &mut self, - name: impl Into, - namespace: FnNamespace, - access: FnAccess, - arg_names: Option<&[&str]>, - arg_types: impl AsRef<[TypeId]>, - comments: impl IntoIterator, - func: CallableFunction, - ) -> u64 { - let arg_names = arg_names.unwrap_or(&[]); - self._set_fn( - name, namespace, access, arg_names, arg_types, comments, func, - ) - .metadata - .hash - } - - /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key. - /// - /// If there is an existing Rust function of the same hash, it is replaced. - #[inline] - fn _set_fn, C: AsRef>( - &mut self, - name: impl Into, - namespace: FnNamespace, - access: FnAccess, - arg_names: impl IntoIterator, - arg_types: impl AsRef<[TypeId]>, - comments: impl IntoIterator, - func: CallableFunction, - ) -> &mut FuncInfo { - let _arg_names = arg_names; - let _comments = comments; - let is_method = func.is_method(); - - let param_types = arg_types - .as_ref() - .iter() - .enumerate() - .map(|(i, &type_id)| Self::map_type(!is_method || i > 0, type_id)) - .collect::>(); - - let is_dynamic = param_types - .iter() - .any(|&type_id| type_id == TypeId::of::()); - - #[cfg(feature = "metadata")] - let (param_names, return_type_name) = { - let mut names = _arg_names - .into_iter() - .map(|a| a.as_ref().into()) - .collect::>(); - let return_type = if names.len() > param_types.len() { - names.pop().unwrap() - } else { - crate::SmartString::new_const() - }; - names.shrink_to_fit(); - (names, return_type) - }; - - let name = name.into(); - let hash_base = calc_fn_hash(None, &name, param_types.len()); - let hash_fn = calc_fn_hash_full(hash_base, param_types.iter().copied()); - - // Catch hash collisions in testing environment only. - #[cfg(feature = "testing-environ")] - if let Some(f) = self.functions.as_ref().and_then(|f| f.get(&hash_base)) { - unreachable!( - "Hash {} already exists when registering function {}:\n{:#?}", - hash_base, name, f - ); - } - - if is_dynamic { - self.dynamic_functions_filter.mark(hash_base); - } - - self.flags - .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS); - - let f = FuncInfo { - func, - metadata: FuncInfoMetadata { - hash: hash_fn, - name, - namespace, - access, - #[cfg(not(feature = "no_object"))] - this_type: None, - num_params: param_types.len(), - param_types: param_types.into_boxed_slice(), - #[cfg(feature = "metadata")] - params_info: param_names.into_boxed_slice(), - #[cfg(feature = "metadata")] - return_type: return_type_name, - #[cfg(feature = "metadata")] - comments: _comments.into_iter().map(|s| s.as_ref().into()).collect(), - } - .into(), - }; - - match self - .functions - .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE)) - .entry(hash_fn) - { - Entry::Occupied(mut entry) => { - entry.insert(f); - entry.into_mut() - } - Entry::Vacant(entry) => entry.insert(f), - } - } - - /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key. - /// - /// If there is a similar existing Rust function, it is replaced. - /// - /// # Assumptions - /// - /// * The function is assumed to be _non-pure_. - /// - /// * The function is assumed to be _volatile_ -- i.e. it does not guarantee the same result for the same input(s). - /// - /// # WARNING - Low Level API - /// - /// This function is very low level. - /// - /// # Arguments - /// - /// A list of [`TypeId`]'s is taken as the argument types. - /// - /// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][Dynamic], - /// which is guaranteed to contain enough arguments of the correct types. - /// - /// The function is assumed to be a _method_, meaning that the first argument should not be consumed. - /// All other arguments can be consumed. - /// - /// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()` - /// - /// To access an argument value and avoid cloning, use `args[n].take().cast::()`. - /// Notice that this will _consume_ the argument, replacing it with `()`. - /// - /// To access the first mutable argument, use `args.get_mut(0).unwrap()` - /// - /// # Function Metadata - /// - /// No metadata for the function is registered. Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. - /// - /// # Example - /// - /// ``` - /// use rhai::{Module, FnNamespace, FnAccess}; - /// - /// let mut module = Module::new(); - /// let hash = module.set_raw_fn("double_or_not", FnNamespace::Internal, FnAccess::Public, - /// // Pass parameter types via a slice with TypeId's - /// &[std::any::TypeId::of::(), std::any::TypeId::of::()], - /// // Fixed closure signature - /// |context, args| { - /// // 'args' is guaranteed to be the right length and of the correct types - /// - /// // Get the second parameter by 'consuming' it - /// let double = args[1].take().cast::(); - /// // Since it is a primary type, it can also be cheaply copied - /// let double = args[1].clone_cast::(); - /// // Get a mutable reference to the first argument. - /// let mut x = args[0].write_lock::().unwrap(); - /// - /// let orig = *x; - /// - /// if double { - /// *x *= 2; // the first argument can be mutated - /// } - /// - /// Ok(orig) // return RhaiResult - /// }); - /// - /// assert!(module.contains_fn(hash)); - /// ``` - #[inline(always)] - pub fn set_raw_fn( - &mut self, - name: impl Into, - namespace: FnNamespace, - access: FnAccess, - arg_types: impl AsRef<[TypeId]>, - func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf + SendSync + 'static, - ) -> u64 { - let f = move |ctx: Option, args: &mut FnCallArgs| { - func(ctx.unwrap(), args).map(Dynamic::from) - }; - - self.set_fn( - name, - namespace, - access, - None, - arg_types, - CallableFunction::Method { - func: Shared::new(f), - has_context: true, - is_pure: false, - is_volatile: true, - }, - ) + func: RhaiFunc, + ) -> &FuncMetadata { + options.set_into_module_raw(self, arg_types, func) } /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key. @@ -1400,15 +1243,11 @@ impl Module { /// /// * The function is assumed to be _volatile_ -- i.e. it does not guarantee the same result for the same input(s). /// - /// # Function Namespace + /// * The function namespace is [`FnNamespace::Internal`]. /// - /// The default function namespace is [`FnNamespace::Internal`]. - /// Use [`update_fn_namespace`][Module::update_fn_namespace] to change it. + /// * No metadata for the function is registered. /// - /// # Function Metadata - /// - /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// To change this, use the [`FuncRegistration`] API instead. /// /// # Example /// @@ -1419,34 +1258,16 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline] - pub fn set_native_fn( + pub fn set_native_fn( &mut self, name: impl Into, - func: F, + func: FUNC, ) -> u64 where - T: Variant + Clone, - F: RegisterNativeFunction + SendSync + 'static, + R: Variant + Clone, + FUNC: RhaiNativeFunc + SendSync + 'static, { - let fn_name = name.into(); - let is_pure = true; - - #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - let is_pure = is_pure && (F::num_params() != 3 || fn_name != crate::engine::FN_IDX_SET); - #[cfg(not(feature = "no_object"))] - let is_pure = - is_pure && (F::num_params() != 2 || !fn_name.starts_with(crate::engine::FN_SET)); - - let func = func.into_callable_function(fn_name.clone(), is_pure, true); - - self.set_fn( - fn_name, - FnNamespace::Internal, - FnAccess::Public, - None, - F::param_types(), - func, - ) + FuncRegistration::new(name).set_into_module(self, func).hash } /// Set a Rust getter function taking one mutable parameter, returning a [`u64`] hash key. @@ -1461,7 +1282,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1473,23 +1295,20 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_getter_fn(&mut self, name: impl AsRef, func: F) -> u64 + pub fn set_getter_fn( + &mut self, + name: impl AsRef, + func: FUNC, + ) -> u64 where A: Variant + Clone, - T: Variant + Clone, - F: RegisterNativeFunction<(Mut,), 1, C, T, true> + SendSync + 'static, + R: Variant + Clone, + FUNC: RhaiNativeFunc<(Mut,), 1, X, R, true> + SendSync + 'static, { - let fn_name = crate::engine::make_getter(name.as_ref()); - let func = func.into_callable_function(fn_name.clone(), true, true); - - self.set_fn( - fn_name, - FnNamespace::Global, - FnAccess::Public, - None, - F::param_types(), - func, - ) + FuncRegistration::new(crate::engine::make_getter(name.as_ref())) + .with_namespace(FnNamespace::Global) + .set_into_module(self, func) + .hash } /// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`], @@ -1505,7 +1324,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1521,23 +1341,20 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_setter_fn(&mut self, name: impl AsRef, func: F) -> u64 + pub fn set_setter_fn( + &mut self, + name: impl AsRef, + func: FUNC, + ) -> u64 where A: Variant + Clone, - T: Variant + Clone, - F: RegisterNativeFunction<(Mut, T), 2, C, (), true> + SendSync + 'static, + R: Variant + Clone, + FUNC: RhaiNativeFunc<(Mut, R), 2, X, (), true> + SendSync + 'static, { - let fn_name = crate::engine::make_setter(name.as_ref()); - let func = func.into_callable_function(fn_name.clone(), false, true); - - self.set_fn( - fn_name, - FnNamespace::Global, - FnAccess::Public, - None, - F::param_types(), - func, - ) + FuncRegistration::new(crate::engine::make_setter(name.as_ref())) + .with_namespace(FnNamespace::Global) + .set_into_module(self, func) + .hash } /// Set a pair of Rust getter and setter functions into the [`Module`], returning both [`u64`] hash keys. @@ -1550,7 +1367,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1572,14 +1390,14 @@ impl Module { #[inline(always)] pub fn set_getter_setter_fn< A: Variant + Clone, - const C1: bool, - const C2: bool, - T: Variant + Clone, + const X1: bool, + const X2: bool, + R: Variant + Clone, >( &mut self, name: impl AsRef, - getter: impl RegisterNativeFunction<(Mut,), 1, C1, T, true> + SendSync + 'static, - setter: impl RegisterNativeFunction<(Mut, T), 2, C2, (), true> + SendSync + 'static, + getter: impl RhaiNativeFunc<(Mut,), 1, X1, R, true> + SendSync + 'static, + setter: impl RhaiNativeFunc<(Mut, R), 2, X2, (), true> + SendSync + 'static, ) -> (u64, u64) { ( self.set_getter_fn(name.as_ref(), getter), @@ -1605,7 +1423,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1620,12 +1439,12 @@ impl Module { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn set_indexer_get_fn(&mut self, func: F) -> u64 + pub fn set_indexer_get_fn(&mut self, func: FUNC) -> u64 where A: Variant + Clone, B: Variant + Clone, - T: Variant + Clone, - F: RegisterNativeFunction<(Mut, B), 2, C, T, true> + SendSync + 'static, + R: Variant + Clone, + FUNC: RhaiNativeFunc<(Mut, B), 2, X, R, true> + SendSync + 'static, { #[cfg(not(feature = "no_index"))] assert!( @@ -1645,14 +1464,10 @@ impl Module { "Cannot register indexer for strings." ); - self.set_fn( - crate::engine::FN_IDX_GET, - FnNamespace::Global, - FnAccess::Public, - None, - F::param_types(), - func.into_callable_function(crate::engine::FN_IDX_GET.into(), true, true), - ) + FuncRegistration::new(crate::engine::FN_IDX_GET) + .with_namespace(FnNamespace::Global) + .set_into_module(self, func) + .hash } /// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`], @@ -1673,7 +1488,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1688,12 +1504,12 @@ impl Module { /// ``` #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline] - pub fn set_indexer_set_fn(&mut self, func: F) -> u64 + pub fn set_indexer_set_fn(&mut self, func: FUNC) -> u64 where A: Variant + Clone, B: Variant + Clone, - T: Variant + Clone, - F: RegisterNativeFunction<(Mut, B, T), 3, C, (), true> + SendSync + 'static, + R: Variant + Clone, + FUNC: RhaiNativeFunc<(Mut, B, R), 3, X, (), true> + SendSync + 'static, { #[cfg(not(feature = "no_index"))] assert!( @@ -1713,14 +1529,10 @@ impl Module { "Cannot register indexer for strings." ); - self.set_fn( - crate::engine::FN_IDX_SET, - FnNamespace::Global, - FnAccess::Public, - None, - F::param_types(), - func.into_callable_function(crate::engine::FN_IDX_SET.into(), false, true), - ) + FuncRegistration::new(crate::engine::FN_IDX_SET) + .with_namespace(FnNamespace::Global) + .set_into_module(self, func) + .hash } /// Set a pair of Rust index getter and setter functions into the [`Module`], returning both [`u64`] hash keys. @@ -1739,7 +1551,8 @@ impl Module { /// # Function Metadata /// /// No metadata for the function is registered. - /// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata. + /// + /// Use the [`FuncRegistration`] API instead to add metadata. /// /// # Example /// @@ -1763,13 +1576,13 @@ impl Module { pub fn set_indexer_get_set_fn< A: Variant + Clone, B: Variant + Clone, - const C1: bool, - const C2: bool, - T: Variant + Clone, + const X1: bool, + const X2: bool, + R: Variant + Clone, >( &mut self, - get_fn: impl RegisterNativeFunction<(Mut, B), 2, C1, T, true> + SendSync + 'static, - set_fn: impl RegisterNativeFunction<(Mut, B, T), 3, C2, (), true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Mut, B), 2, X1, R, true> + SendSync + 'static, + set_fn: impl RhaiNativeFunc<(Mut, B, R), 3, X2, (), true> + SendSync + 'static, ) -> (u64, u64) { ( self.set_indexer_get_fn(get_fn), @@ -1782,11 +1595,11 @@ impl Module { /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. #[inline] #[must_use] - pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> { + pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&RhaiFunc> { self.functions .as_ref() .and_then(|m| m.get(&hash_native)) - .map(|f| &f.func) + .map(|(f, _)| f) } /// Can the particular function with [`Dynamic`] parameter(s) exist in the [`Module`]? @@ -1815,7 +1628,7 @@ impl Module { #[cfg(not(feature = "no_module"))] #[inline] #[must_use] - pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> { + pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&RhaiFunc> { self.all_functions .as_ref() .and_then(|m| m.get(&hash_qualified_fn)) @@ -1958,14 +1771,8 @@ impl Module { Some(ref mut m) => m.extend( functions .iter() - .filter(|(.., f)| { - _filter( - f.metadata.namespace, - f.metadata.access, - f.func.is_script(), - &f.metadata.name, - f.metadata.num_params, - ) + .filter(|(.., (f, m))| { + _filter(m.namespace, m.access, f.is_script(), &m.name, m.num_params) }) .map(|(&k, f)| (k, f.clone())), ), @@ -2001,14 +1808,9 @@ impl Module { ) -> &mut Self { self.functions = std::mem::take(&mut self.functions).map(|m| { m.into_iter() - .filter(|(.., f)| { - if f.func.is_script() { - filter( - f.metadata.namespace, - f.metadata.access, - &f.metadata.name, - f.metadata.num_params, - ) + .filter(|(.., (f, m))| { + if f.is_script() { + filter(m.namespace, m.access, &m.name, m.num_params) } else { false } @@ -2070,8 +1872,11 @@ impl Module { /// Get an iterator to the functions in the [`Module`]. #[inline] #[allow(dead_code)] - pub(crate) fn iter_fn(&self) -> impl Iterator { - self.functions.iter().flat_map(StraightHashMap::values) + pub(crate) fn iter_fn(&self) -> impl Iterator { + self.functions + .iter() + .flat_map(StraightHashMap::values) + .map(|(f, m)| (f, &**m)) } /// Get an iterator over all script-defined functions in the [`Module`]. @@ -2081,7 +1886,7 @@ impl Module { /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]). /// 3) Function name (as string slice). /// 4) Number of parameters. - /// 5) Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef]. + /// 5) Shared reference to function definition [`ScriptFuncDef`][crate::ast::ScriptFuncDef]. #[cfg(not(feature = "no_function"))] #[inline] pub(crate) fn iter_script_fn( @@ -2092,16 +1897,16 @@ impl Module { FnAccess, &str, usize, - &Shared, + &Shared, ), > + '_ { - self.iter_fn().filter(|&f| f.func.is_script()).map(|f| { + self.iter_fn().filter(|(f, _)| f.is_script()).map(|(f, m)| { ( - f.metadata.namespace, - f.metadata.access, - f.metadata.name.as_str(), - f.metadata.num_params, - f.func.get_script_fn_def().expect("`ScriptFnDef`"), + m.namespace, + m.access, + m.name.as_str(), + m.num_params, + f.get_script_fn_def().expect("`ScriptFuncDef`"), ) }) } @@ -2119,14 +1924,9 @@ impl Module { pub fn iter_script_fn_info( &self, ) -> impl Iterator { - self.iter_fn().filter(|&f| f.func.is_script()).map(|f| { - ( - f.metadata.namespace, - f.metadata.access, - f.metadata.name.as_str(), - f.metadata.num_params, - ) - }) + self.iter_fn() + .filter(|(f, _)| f.is_script()) + .map(|(_, f)| (f.namespace, f.access, f.name.as_str(), f.num_params)) } /// _(internals)_ Get an iterator over all script-defined functions in the [`Module`]. @@ -2137,7 +1937,7 @@ impl Module { /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]). /// 3) Function name (as string slice). /// 4) Number of parameters. - /// 5) _(internals)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef]. + /// 5) _(internals)_ Shared reference to function definition [`ScriptFuncDef`][crate::ast::ScriptFuncDef]. #[cfg(not(feature = "no_function"))] #[cfg(feature = "internals")] #[inline(always)] @@ -2149,7 +1949,7 @@ impl Module { FnAccess, &str, usize, - &Shared, + &Shared, ), > { self.iter_script_fn() @@ -2251,7 +2051,7 @@ impl Module { let _ = result?; // Encapsulated environment - let environ = Shared::new(crate::func::EncapsulatedEnviron { + let environ = Shared::new(crate::ast::EncapsulatedEnviron { #[cfg(not(feature = "no_function"))] lib: ast.shared_lib().clone(), imports, @@ -2317,13 +2117,14 @@ impl Module { }) .for_each(|f| { let hash = module.set_script_fn(f.clone()); - let f = module.functions.as_mut().unwrap().get_mut(&hash).unwrap(); - - // Encapsulate AST environment - if let CallableFunction::Script { - environ: ref mut e, .. - } = f.func + if let ( + RhaiFunc::Script { + environ: ref mut e, .. + }, + _, + ) = module.functions.as_mut().unwrap().get_mut(&hash).unwrap() { + // Encapsulate AST environment *e = Some(environ.clone()); } }); @@ -2359,8 +2160,8 @@ impl Module { module: &'a Module, path: &mut Vec<&'a str>, variables: &mut StraightHashMap, - functions: &mut StraightHashMap, - type_iterators: &mut BTreeMap>, + functions: &mut StraightHashMap, + type_iterators: &mut BTreeMap>, ) -> bool { let mut contains_indexed_global_functions = false; @@ -2395,40 +2196,38 @@ impl Module { } // Index all functions - for (&hash, f) in module.functions.iter().flatten() { - match f.metadata.namespace { + for (&hash, (f, m)) in module.functions.iter().flatten() { + match m.namespace { FnNamespace::Global => { // Catch hash collisions in testing environment only. #[cfg(feature = "testing-environ")] if let Some(fx) = functions.get(&hash) { unreachable!( "Hash {} already exists when indexing function {:#?}:\n{:#?}", - hash, f.func, fx + hash, f, fx ); } // Flatten all functions with global namespace - functions.insert(hash, f.func.clone()); + functions.insert(hash, f.clone()); contains_indexed_global_functions = true; } FnNamespace::Internal => (), } - match f.metadata.access { + match m.access { FnAccess::Public => (), FnAccess::Private => continue, // Do not index private functions } - if f.func.is_script() { + if f.is_script() { #[cfg(not(feature = "no_function"))] { - let hash_script = crate::calc_fn_hash( - path.iter().copied(), - &f.metadata.name, - f.metadata.num_params, - ); + let hash_script = + crate::calc_fn_hash(path.iter().copied(), &m.name, m.num_params); #[cfg(not(feature = "no_object"))] let hash_script = f - .metadata + .get_script_fn_def() + .unwrap() .this_type .as_ref() .map_or(hash_script, |this_type| { @@ -2440,29 +2239,26 @@ impl Module { if let Some(fx) = functions.get(&hash_script) { unreachable!( "Hash {} already exists when indexing function {:#?}:\n{:#?}", - hash_script, f.func, fx + hash_script, f, fx ); } - functions.insert(hash_script, f.func.clone()); + functions.insert(hash_script, f.clone()); } } else { - let hash_fn = calc_native_fn_hash( - path.iter().copied(), - &f.metadata.name, - &f.metadata.param_types, - ); + let hash_fn = + calc_native_fn_hash(path.iter().copied(), &m.name, &m.param_types); // Catch hash collisions in testing environment only. #[cfg(feature = "testing-environ")] if let Some(fx) = functions.get(&hash_fn) { unreachable!( "Hash {} already exists when indexing function {:#?}:\n{:#?}", - hash_fn, f.func, fx + hash_fn, f, fx ); } - functions.insert(hash_fn, f.func.clone()); + functions.insert(hash_fn, f.clone()); } } @@ -2592,14 +2388,14 @@ impl Module { #[cfg(not(feature = "no_module"))] #[inline] #[must_use] - pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> { + pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&FnIterator> { self.all_type_iterators.get(&id).map(|f| &**f) } /// Get the specified type iterator. #[inline] #[must_use] - pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> { + pub(crate) fn get_iter(&self, id: TypeId) -> Option<&FnIterator> { self.type_iterators.get(&id).map(|f| &**f) } } diff --git a/src/optimizer.rs b/src/optimizer.rs index ebc9f5209..4b0992c65 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -389,6 +389,16 @@ impl StmtBlock { } } +/// Is this [`Expr`] a constant that is hashable? +#[inline(always)] +fn is_hashable_constant(expr: &Expr) -> bool { + match expr { + _ if !expr.is_constant() => false, + Expr::DynamicConstant(v, ..) => v.is_hashable(), + _ => false, + } +} + /// Optimize a [statement][Stmt]. fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: bool) { #[inline(always)] @@ -505,7 +515,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b } // switch const { ... } - Stmt::Switch(x, pos) if x.0.is_constant() => { + Stmt::Switch(x, pos) if is_hashable_constant(&x.0) => { let ( match_expr, SwitchCasesCollection { @@ -529,23 +539,22 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b let mut b = mem::take(&mut expressions[*index]); cases.clear(); - if b.is_always_true() { + if matches!(b.lhs, Expr::BoolConstant(true, ..)) { // Promote the matched case - let mut statements = Stmt::Expr(b.expr.take().into()); + let mut statements = Stmt::Expr(b.rhs.take().into()); optimize_stmt(&mut statements, state, true); *stmt = statements; } else { // switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def } - optimize_expr(&mut b.condition, state, false); + optimize_expr(&mut b.lhs, state, false); let branch = def_case.map_or(StmtBlock::NONE, |index| { - let mut def_stmt = - Stmt::Expr(expressions[index].expr.take().into()); + let mut def_stmt = Stmt::Expr(expressions[index].rhs.take().into()); optimize_stmt(&mut def_stmt, state, true); def_stmt.into() }); - let body = Stmt::Expr(b.expr.take().into()).into(); - let expr = b.condition.take(); + let body = Stmt::Expr(b.rhs.take().into()).into(); + let expr = b.lhs.take(); *stmt = Stmt::If( FlowControl { expr, body, branch }.into(), @@ -560,9 +569,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b for &index in case_blocks_list { let mut b = mem::take(&mut expressions[index]); - if b.is_always_true() { + if matches!(b.lhs, Expr::BoolConstant(true, ..)) { // Promote the matched case - let mut statements = Stmt::Expr(b.expr.take().into()); + let mut statements = Stmt::Expr(b.rhs.take().into()); optimize_stmt(&mut statements, state, true); *stmt = statements; state.set_dirty(); @@ -579,31 +588,30 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b if ranges.len() == 1 || ranges .iter() - .all(|r| expressions[r.index()].is_always_true()) + .all(|r| matches!(expressions[r.index()].lhs, Expr::BoolConstant(true, ..))) { if let Some(r) = ranges.iter().find(|r| r.contains(&value)) { let range_block = &mut expressions[r.index()]; - if range_block.is_always_true() { + if matches!(range_block.lhs, Expr::BoolConstant(true, ..)) { // Promote the matched case let block = &mut expressions[r.index()]; - let mut statements = Stmt::Expr(block.expr.take().into()); + let mut statements = Stmt::Expr(block.rhs.take().into()); optimize_stmt(&mut statements, state, true); *stmt = statements; } else { - let mut expr = range_block.condition.take(); + let mut expr = range_block.lhs.take(); // switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def } optimize_expr(&mut expr, state, false); let branch = def_case.map_or(StmtBlock::NONE, |index| { - let mut def_stmt = - Stmt::Expr(expressions[index].expr.take().into()); + let mut def_stmt = Stmt::Expr(expressions[index].rhs.take().into()); optimize_stmt(&mut def_stmt, state, true); def_stmt.into() }); - let body = Stmt::Expr(expressions[r.index()].expr.take().into()).into(); + let body = Stmt::Expr(expressions[r.index()].rhs.take().into()).into(); *stmt = Stmt::If( FlowControl { expr, body, branch }.into(), @@ -631,8 +639,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b for r in ranges { let b = &mut expressions[r.index()]; - optimize_expr(&mut b.condition, state, false); - optimize_expr(&mut b.expr, state, false); + optimize_expr(&mut b.lhs, state, false); + optimize_expr(&mut b.rhs, state, false); } return; } @@ -643,7 +651,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match def_case { Some(index) => { - let mut def_stmt = Stmt::Expr(expressions[*index].expr.take().into()); + let mut def_stmt = Stmt::Expr(expressions[*index].rhs.take().into()); optimize_stmt(&mut def_stmt, state, true); *stmt = def_stmt; } @@ -667,11 +675,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b // Optimize blocks for b in &mut *expressions { - optimize_expr(&mut b.condition, state, false); - optimize_expr(&mut b.expr, state, false); + optimize_expr(&mut b.lhs, state, false); + optimize_expr(&mut b.rhs, state, false); - if b.is_always_false() && !b.expr.is_unit() { - b.expr = Expr::Unit(b.expr.position()); + if matches!(b.lhs, Expr::BoolConstant(false, ..)) && !b.rhs.is_unit() { + b.rhs = Expr::Unit(b.rhs.position()); state.set_dirty(); } } @@ -680,7 +688,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b cases.retain(|_, list| { // Remove all entries that have false conditions list.retain(|index| { - if expressions[*index].is_always_false() { + if matches!(expressions[*index].lhs, Expr::BoolConstant(false, ..)) { state.set_dirty(); false } else { @@ -688,10 +696,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b } }); // Remove all entries after a `true` condition - if let Some(n) = list - .iter() - .position(|&index| expressions[index].is_always_true()) - { + if let Some(n) = list.iter().position(|&index| { + matches!(expressions[index].lhs, Expr::BoolConstant(true, ..)) + }) { if n + 1 < list.len() { state.set_dirty(); list.truncate(n + 1); @@ -708,7 +715,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b // Remove false ranges ranges.retain(|r| { - if expressions[r.index()].is_always_false() { + if matches!(expressions[r.index()].lhs, Expr::BoolConstant(false, ..)) { state.set_dirty(); false } else { @@ -717,7 +724,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b }); if let Some(index) = def_case { - optimize_expr(&mut expressions[*index].expr, state, false); + optimize_expr(&mut expressions[*index].rhs, state, false); } // Remove unused block statements @@ -725,9 +732,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b if *def_case != Some(index) && cases.values().flat_map(|c| c.iter()).all(|&n| n != index) && ranges.iter().all(|r| r.index() != index) - && !b.expr.is_unit() + && !b.rhs.is_unit() { - b.expr = Expr::Unit(b.expr.position()); + b.rhs = Expr::Unit(b.rhs.position()); state.set_dirty(); } }); @@ -1365,7 +1372,7 @@ pub fn optimize_into_ast( engine: &Engine, scope: Option<&Scope>, statements: StmtBlockContainer, - #[cfg(not(feature = "no_function"))] functions: Vec>, + #[cfg(not(feature = "no_function"))] functions: Vec>, optimization_level: OptimizationLevel, ) -> AST { let mut statements = statements; @@ -1384,7 +1391,7 @@ pub fn optimize_into_ast( functions .iter() - .map(|fn_def| crate::ast::ScriptFnDef { + .map(|fn_def| crate::ast::ScriptFuncDef { name: fn_def.name.clone(), access: fn_def.access, body: crate::ast::StmtBlock::NONE, diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 7172c617b..f5d9ea93e 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -12,7 +12,6 @@ use crate::{ #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{any::TypeId, cmp::Ordering, mem}; -use thin_vec::ThinVec; def_package! { /// Package of basic array utilities. @@ -1272,7 +1271,7 @@ pub mod array_functions { pub fn dedup(ctx: NativeCallContext, array: &mut Array) { let comparer = FnPtr { name: ctx.engine().get_interned_string(OP_EQUALS), - curry: ThinVec::new(), + curry: <_>::default(), environ: None, #[cfg(not(feature = "no_function"))] fn_def: None, diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 7e43705f1..a4f0417ae 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -244,6 +244,7 @@ macro_rules! reg_range { let _hash = $lib.set_native_fn($x, |from: $y, to: $y| Ok(from..to)); #[cfg(feature = "metadata")] + #[allow(deprecated)] $lib.update_fn_metadata_with_comments(_hash, [ concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), @@ -277,6 +278,7 @@ macro_rules! reg_range { let _hash = $lib.set_native_fn($x, |from: $y, to: $y, step: $y| StepRange::new(from, to, step, $add)); #[cfg(feature = "metadata")] + #[allow(deprecated)] $lib.update_fn_metadata_with_comments(_hash, [ concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), @@ -308,6 +310,7 @@ macro_rules! reg_range { let _hash = $lib.set_native_fn($x, |range: std::ops::Range<$y>, step: $y| StepRange::new(range.start, range.end, step, $add)); #[cfg(feature = "metadata")] + #[allow(deprecated)] $lib.update_fn_metadata_with_comments(_hash, [ concat!("range: Range<", stringify!($y), ">"), concat!("step: ", stringify!($y)), @@ -385,6 +388,7 @@ def_package! { Ok(CharsStream::new(string, from, to - from)) }); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &str", &range_type, "Iterator"], @@ -407,6 +411,7 @@ def_package! { Ok(CharsStream::new(string, from, to-from + 1)) }); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &str", &range_inclusive_type, "Iterator"], @@ -425,6 +430,7 @@ def_package! { let _hash = lib.set_native_fn("chars", |string, from, len| Ok(CharsStream::new(string, from, len))); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &str", "start: INT", "len: INT", "Iterator"], @@ -449,6 +455,7 @@ def_package! { let _hash = lib.set_native_fn("chars", |string, from| Ok(CharsStream::new(string, from, INT::MAX))); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &str", "from: INT", "Iterator"], @@ -471,6 +478,7 @@ def_package! { let _hash = lib.set_native_fn("chars", |string| Ok(CharsStream::new(string, 0, INT::MAX))); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &str", "Iterator"], @@ -491,6 +499,7 @@ def_package! { { let _hash = lib.set_getter_fn("chars", |string: &mut ImmutableString| Ok(CharsStream::new(string, 0, INT::MAX))); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["string: &mut ImmutableString", "Iterator"], @@ -517,6 +526,7 @@ def_package! { BitRange::new(value, from, to - from) }); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: INT", &range_type, "Iterator"], @@ -541,6 +551,7 @@ def_package! { BitRange::new(value, from, to - from + 1) }); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: INT", &range_inclusive_type, "Iterator"], @@ -561,6 +572,7 @@ def_package! { let _hash = lib.set_native_fn("bits", BitRange::new); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: INT", "from: INT", "len: INT", "Iterator"], @@ -585,6 +597,7 @@ def_package! { let _hash = lib.set_native_fn("bits", |value, from| BitRange::new(value, from, INT::MAX)); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: INT", "from: INT", "Iterator"], @@ -607,6 +620,7 @@ def_package! { let _hash = lib.set_native_fn("bits", |value| BitRange::new(value, 0, INT::MAX) ); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: INT", "Iterator"], @@ -629,6 +643,7 @@ def_package! { { let _hash = lib.set_getter_fn("bits", |value: &mut INT| BitRange::new(*value, 0, INT::MAX) ); #[cfg(feature = "metadata")] + #[allow(deprecated)] lib.update_fn_metadata_with_comments( _hash, ["value: &mut INT", "Iterator"], diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index 8f1ded8ce..1efc688cc 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -32,7 +32,7 @@ mod core_functions { /// ```rhai /// exit(42); /// ``` - #[rhai_fn(name = "exit", return_raw)] + #[rhai_fn(name = "exit", volatile, return_raw)] pub fn exit_with_value(value: Dynamic) -> RhaiResult { Err(ERR::Exit(value, Position::NONE).into()) } @@ -42,7 +42,7 @@ mod core_functions { /// ```rhai /// exit(); /// ``` - #[rhai_fn(return_raw)] + #[rhai_fn(volatile, return_raw)] pub fn exit() -> RhaiResult { Err(ERR::Exit(Dynamic::UNIT, Position::NONE).into()) } @@ -134,9 +134,9 @@ mod core_functions { /// ``` #[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_std"))] - #[rhai_fn(name = "sleep")] + #[rhai_fn(name = "sleep", volatile)] pub fn sleep_float(seconds: FLOAT) { - if seconds <= 0.0 { + if !seconds.is_normal() || seconds.is_sign_negative() { return; } @@ -154,6 +154,7 @@ mod core_functions { /// sleep(10); /// ``` #[cfg(not(feature = "no_std"))] + #[rhai_fn(volatile)] pub fn sleep(seconds: INT) { if seconds <= 0 { return; @@ -216,18 +217,18 @@ mod reflection_functions { #[cfg(not(feature = "no_object"))] fn collect_fn_metadata( ctx: &NativeCallContext, - filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared) -> bool + filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared) -> bool + Copy, ) -> crate::Array { #[cfg(not(feature = "no_module"))] use crate::Identifier; - use crate::{ast::ScriptFnDef, engine::FN_ANONYMOUS, Array, Map}; + use crate::{ast::ScriptFuncDef, engine::FN_ANONYMOUS, Array, Map}; // Create a metadata record for a function. fn make_metadata( engine: &Engine, #[cfg(not(feature = "no_module"))] namespace: Identifier, - func: &ScriptFnDef, + func: &ScriptFuncDef, ) -> Map { let mut map = Map::new(); @@ -346,7 +347,7 @@ fn collect_fn_metadata( list: &mut Array, namespace: &str, module: &Module, - filter: impl Fn(FnNamespace, FnAccess, &str, usize, &Shared) -> bool + Copy, + filter: impl Fn(FnNamespace, FnAccess, &str, usize, &Shared) -> bool + Copy, ) { module .iter_script_fn() diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 3f427f0b8..06f1d93c7 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -377,13 +377,13 @@ mod decimal_functions { /// Return the natural number _e_. #[cfg(feature = "no_float")] #[rhai_fn(name = "PI")] - pub fn pi() -> Decimal { + pub const fn pi() -> Decimal { Decimal::PI } /// Return the number π. #[cfg(feature = "no_float")] #[rhai_fn(name = "E")] - pub fn e() -> Decimal { + pub const fn e() -> Decimal { Decimal::E } /// Parse a string into a decimal number. diff --git a/src/parser.rs b/src/parser.rs index 56c7146fb..0d6559427 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,9 +2,9 @@ use crate::api::options::LangOptions; use crate::ast::{ - ASTFlags, BinaryExpr, CaseBlocksList, ConditionalExpr, Expr, FlowControl, FnCallExpr, - FnCallHashes, Ident, Namespace, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, - StmtBlockContainer, SwitchCasesCollection, + ASTFlags, BinaryExpr, CaseBlocksList, Expr, FlowControl, FnCallExpr, FnCallHashes, Ident, + Namespace, OpAssignment, RangeCase, ScriptFuncDef, Stmt, StmtBlock, StmtBlockContainer, + SwitchCasesCollection, }; use crate::engine::{Precedence, OP_CONTAINS, OP_NOT}; use crate::eval::{Caches, GlobalRuntimeState}; @@ -35,7 +35,7 @@ use thin_vec::ThinVec; pub type ParseResult = Result; -type FnLib = StraightHashMap>; +type FnLib = StraightHashMap>; /// Invalid variable name that acts as a search barrier in a [`Scope`]. const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $"; @@ -639,7 +639,7 @@ impl Engine { }; let mut _namespace = namespace; - let mut args = Vec::new(); + let mut args = FnArgsVec::new(); match token { // id( @@ -702,7 +702,7 @@ impl Engine { op_token: None, namespace: _namespace, hashes, - args: args.into_boxed_slice(), + args, } .into_fn_call_expr(settings.pos)); } @@ -769,7 +769,7 @@ impl Engine { op_token: None, namespace: _namespace, hashes, - args: args.into_boxed_slice(), + args, } .into_fn_call_expr(settings.pos)); } @@ -1164,9 +1164,9 @@ impl Engine { } } - let mut expressions = ThinVec::::new(); + let mut expressions = FnArgsVec::::new(); let mut cases = StraightHashMap::::default(); - let mut ranges = ThinVec::::new(); + let mut ranges = StaticVec::::new(); let mut def_case = None; let mut def_case_pos = Position::NONE; @@ -1261,7 +1261,11 @@ impl Engine { (Expr::Stmt(stmt_block.into()), need_comma) }; - expressions.push((condition, action_expr).into()); + expressions.push(BinaryExpr { + lhs: condition, + rhs: action_expr, + }); + let index = expressions.len() - 1; if case_expr_list.is_empty() { @@ -1282,14 +1286,11 @@ impl Engine { if let Some(mut r) = range_value { if !r.is_empty() { - // Other range r.set_index(index); ranges.push(r); } - continue; - } - - if !ranges.is_empty() { + } else if !ranges.is_empty() { + // Check for numeric values after ranges let forbidden = match value { Dynamic(Union::Int(..)) => true, #[cfg(not(feature = "no_float"))] @@ -1470,6 +1471,14 @@ impl Engine { // | ... #[cfg(not(feature = "no_function"))] + #[cfg(not(feature = "unchecked"))] + Token::Pipe | Token::Or + if settings.has_option(LangOptions::ANON_FN) + && lib.len() >= self.max_functions() => + { + return Err(PERR::TooManyFunctions.into_err(settings.pos)); + } + #[cfg(not(feature = "no_function"))] Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => { // Build new parse state let new_interner = &mut StringsInterner::new(); @@ -1990,7 +1999,7 @@ impl Engine { namespace: Namespace::NONE, name: state.get_interned_string("-"), hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "-", 1)), - args: vec![expr].into_boxed_slice(), + args: IntoIterator::into_iter([expr]).collect(), op_token: Some(token), capture_parent_scope: false, } @@ -2012,7 +2021,7 @@ impl Engine { namespace: Namespace::NONE, name: state.get_interned_string("+"), hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "+", 1)), - args: vec![expr].into_boxed_slice(), + args: IntoIterator::into_iter([expr]).collect(), op_token: Some(token), capture_parent_scope: false, } @@ -2028,8 +2037,10 @@ impl Engine { namespace: Namespace::NONE, name: state.get_interned_string("!"), hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "!", 1)), - args: vec![self.parse_unary(input, state, lib, settings.level_up()?)?] - .into_boxed_slice(), + args: { + let expr = self.parse_unary(input, state, lib, settings.level_up()?)?; + IntoIterator::into_iter([expr]).collect() + }, op_token: Some(token), capture_parent_scope: false, } @@ -2387,7 +2398,7 @@ impl Engine { namespace: Namespace::NONE, name: state.get_interned_string(&op), hashes: FnCallHashes::from_native_only(hash), - args: vec![root, rhs].into_boxed_slice(), + args: IntoIterator::into_iter([root, rhs]).collect(), op_token: native_only.then(|| op_token.clone()), capture_parent_scope: false, }; @@ -2440,7 +2451,7 @@ impl Engine { namespace: Namespace::NONE, name: state.get_interned_string(OP_NOT), hashes: FnCallHashes::from_native_only(calc_fn_hash(None, OP_NOT, 1)), - args: vec![fn_call].into_boxed_slice(), + args: IntoIterator::into_iter([fn_call]).collect(), op_token: Some(Token::Bang), capture_parent_scope: false, }; @@ -2485,9 +2496,9 @@ impl Engine { let pos = settings.pos; - let mut inputs = Vec::new(); - let mut segments = Vec::new(); - let mut tokens = Vec::new(); + let mut inputs = FnArgsVec::new(); + let mut segments = FnArgsVec::new(); + let mut tokens = FnArgsVec::new(); // Adjust the variables stack if syntax.scope_may_be_changed { @@ -2655,8 +2666,8 @@ impl Engine { Ok(Expr::Custom( crate::ast::CustomExpr { - inputs: inputs.into_boxed_slice(), - tokens: tokens.into_boxed_slice(), + inputs, + tokens, state: user_state, scope_may_be_changed: syntax.scope_may_be_changed, self_terminated, @@ -3343,6 +3354,10 @@ impl Engine { }; match input.next().unwrap() { + #[cfg(not(feature = "unchecked"))] + (Token::Fn, pos) if lib.len() >= self.max_functions() => { + Err(PERR::TooManyFunctions.into_err(pos)) + } (Token::Fn, pos) => { // Build new parse state let new_state = &mut ParseState::new( @@ -3597,7 +3612,7 @@ impl Engine { settings: ParseSettings, access: crate::FnAccess, #[cfg(feature = "metadata")] comments: impl IntoIterator, - ) -> ParseResult { + ) -> ParseResult { let settings = settings.level_up()?; let (token, pos) = input.next().unwrap(); @@ -3709,7 +3724,7 @@ impl Engine { let mut params: FnArgsVec<_> = params.into_iter().map(|(p, ..)| p).collect(); params.shrink_to_fit(); - Ok(ScriptFnDef { + Ok(ScriptFuncDef { name: state.get_interned_string(name), access, #[cfg(not(feature = "no_object"))] @@ -3738,7 +3753,7 @@ impl Engine { } let num_externals = externals.as_ref().len(); - let mut args = Vec::with_capacity(externals.as_ref().len() + 1); + let mut args = FnArgsVec::with_capacity(externals.as_ref().len() + 1); args.push(fn_expr); @@ -3765,7 +3780,7 @@ impl Engine { crate::engine::KEYWORD_FN_PTR_CURRY, num_externals + 1, )), - args: args.into_boxed_slice(), + args, op_token: None, capture_parent_scope: false, } @@ -3797,7 +3812,7 @@ impl Engine { lib: &mut FnLib, settings: ParseSettings, _parent: &mut ParseState, - ) -> ParseResult<(Expr, Shared)> { + ) -> ParseResult<(Expr, Shared)> { use core::iter::FromIterator; let settings = settings.level_up()?; @@ -3875,7 +3890,7 @@ impl Engine { let fn_name = state.get_interned_string(make_anonymous_fn(hash)); // Define the function - let script = Shared::new(ScriptFnDef { + let script = Shared::new(ScriptFuncDef { name: fn_name.clone(), access: crate::FnAccess::Public, #[cfg(not(feature = "no_object"))] @@ -3964,7 +3979,7 @@ impl Engine { mut input: TokenStream, state: &mut ParseState, process_settings: impl FnOnce(&mut ParseSettings), - ) -> ParseResult<(StmtBlockContainer, Vec>)> { + ) -> ParseResult<(StmtBlockContainer, Vec>)> { let mut statements = StmtBlockContainer::new_const(); let mut functions = <_>::default(); diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 60def14b2..3dfd3fbe5 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -2,7 +2,8 @@ #![cfg(feature = "metadata")] use crate::api::formatting::format_type; -use crate::module::{calc_native_fn_hash, FuncInfo, ModuleFlags}; +use crate::func::RhaiFunc; +use crate::module::{calc_native_fn_hash, FuncMetadata, ModuleFlags}; use crate::types::custom_types::CustomTypeInfo; use crate::{calc_fn_hash, Engine, FnAccess, SmartString, AST}; use serde::{Deserialize, Serialize}; @@ -102,15 +103,29 @@ impl Ord for FnMetadata<'_> { } } -impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { - fn from(info: &'a FuncInfo) -> Self { - let base_hash = calc_fn_hash(None, &info.metadata.name, info.metadata.num_params); - let (typ, full_hash) = if info.func.is_script() { - (FnType::Script, base_hash) +impl<'a> From<(&'a RhaiFunc, &'a FuncMetadata)> for FnMetadata<'a> { + fn from(info: (&'a RhaiFunc, &'a FuncMetadata)) -> Self { + let (f, m) = info; + let base_hash = calc_fn_hash(None, &m.name, m.num_params); + let (typ, full_hash, _this_type) = if f.is_script() { + ( + FnType::Script, + base_hash, + #[cfg(not(feature = "no_function"))] + #[cfg(not(feature = "no_object"))] + f.get_script_fn_def() + .unwrap() + .this_type + .as_ref() + .map(|s| s.as_str()), + #[cfg(any(feature = "no_object", feature = "no_function"))] + None::<&str>, + ) } else { ( FnType::Native, - calc_native_fn_hash(None, &info.metadata.name, &info.metadata.param_types), + calc_native_fn_hash(None, &m.name, &m.param_types), + None::<&str>, ) }; @@ -118,17 +133,16 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { base_hash, full_hash, #[cfg(not(feature = "no_module"))] - namespace: info.metadata.namespace, - access: info.metadata.access, - name: &info.metadata.name, + namespace: m.namespace, + access: m.access, + name: &m.name, #[cfg(not(feature = "no_function"))] - is_anonymous: crate::parser::is_anonymous_fn(&info.metadata.name), + is_anonymous: crate::parser::is_anonymous_fn(&m.name), typ, #[cfg(not(feature = "no_object"))] - this_type: info.metadata.this_type.as_deref(), - num_params: info.metadata.num_params, - params: info - .metadata + this_type: _this_type, + num_params: m.num_params, + params: m .params_info .iter() .map(|s| { @@ -141,22 +155,21 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { FnParam { name, typ } }) .collect(), - return_type: format_type(&info.metadata.return_type, true), - signature: info.gen_signature().into(), - doc_comments: if info.func.is_script() { + return_type: format_type(&m.return_type, true), + signature: m.gen_signature().into(), + doc_comments: if f.is_script() { #[cfg(feature = "no_function")] unreachable!("script-defined functions should not exist under no_function"); #[cfg(not(feature = "no_function"))] - info.func - .get_script_fn_def() - .expect("`ScriptFnDef`") + f.get_script_fn_def() + .expect("`ScriptFuncDef`") .comments .iter() .map(<_>::as_ref) .collect() } else { - info.metadata.comments.iter().map(<_>::as_ref).collect() + m.comments.iter().map(<_>::as_ref).collect() }, } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 14cc2fee7..c4030dbde 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -17,7 +17,7 @@ pub struct DynamicSerializer { /// Buffer to hold a temporary key. _key: Identifier, /// Buffer to hold a temporary value. - value: Dynamic, + _value: Dynamic, } impl DynamicSerializer { @@ -26,7 +26,7 @@ impl DynamicSerializer { pub const fn new(value: Dynamic) -> Self { Self { _key: Identifier::new_const(), - value, + _value: value, } } } @@ -464,7 +464,7 @@ impl SerializeSeq for DynamicSerializer { #[cfg(not(feature = "no_index"))] { let value = _value.serialize(&mut *self)?; - let arr = self.value.downcast_mut::().unwrap(); + let arr = self._value.downcast_mut::().unwrap(); arr.push(value); Ok(()) } @@ -481,7 +481,7 @@ impl SerializeSeq for DynamicSerializer { #[inline] fn end(self) -> RhaiResultOf { #[cfg(not(feature = "no_index"))] - return Ok(self.value); + return Ok(self._value); #[cfg(feature = "no_index")] return Err(ERR::ErrorMismatchDataType( "".into(), @@ -500,7 +500,7 @@ impl SerializeTuple for DynamicSerializer { #[cfg(not(feature = "no_index"))] { let value = _value.serialize(&mut *self)?; - let arr = self.value.downcast_mut::().unwrap(); + let arr = self._value.downcast_mut::().unwrap(); arr.push(value); Ok(()) } @@ -516,7 +516,7 @@ impl SerializeTuple for DynamicSerializer { #[inline] fn end(self) -> RhaiResultOf { #[cfg(not(feature = "no_index"))] - return Ok(self.value); + return Ok(self._value); #[cfg(feature = "no_index")] return Err(ERR::ErrorMismatchDataType( "".into(), @@ -535,7 +535,7 @@ impl SerializeTupleStruct for DynamicSerializer { #[cfg(not(feature = "no_index"))] { let value = _value.serialize(&mut *self)?; - let arr = self.value.downcast_mut::().unwrap(); + let arr = self._value.downcast_mut::().unwrap(); arr.push(value); Ok(()) } @@ -551,7 +551,7 @@ impl SerializeTupleStruct for DynamicSerializer { #[inline] fn end(self) -> RhaiResultOf { #[cfg(not(feature = "no_index"))] - return Ok(self.value); + return Ok(self._value); #[cfg(feature = "no_index")] return Err(ERR::ErrorMismatchDataType( "".into(), @@ -592,7 +592,7 @@ impl SerializeMap for DynamicSerializer { { let key = std::mem::take(&mut self._key); let value = _value.serialize(&mut *self)?; - let map = self.value.downcast_mut::().unwrap(); + let map = self._value.downcast_mut::().unwrap(); map.insert(key, value); Ok(()) } @@ -617,7 +617,7 @@ impl SerializeMap for DynamicSerializer { ERR::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE) })?; let value = _value.serialize(&mut *self)?; - let map = self.value.downcast_mut::().unwrap(); + let map = self._value.downcast_mut::().unwrap(); map.insert(key.into(), value); Ok(()) } @@ -633,7 +633,7 @@ impl SerializeMap for DynamicSerializer { #[inline] fn end(self) -> RhaiResultOf { #[cfg(not(feature = "no_object"))] - return Ok(self.value); + return Ok(self._value); #[cfg(feature = "no_object")] return Err(ERR::ErrorMismatchDataType( "".into(), @@ -656,7 +656,7 @@ impl SerializeStruct for DynamicSerializer { #[cfg(not(feature = "no_object"))] { let value = _value.serialize(&mut *self)?; - let map = self.value.downcast_mut::().unwrap(); + let map = self._value.downcast_mut::().unwrap(); map.insert(_key.into(), value); Ok(()) } @@ -672,7 +672,7 @@ impl SerializeStruct for DynamicSerializer { #[inline] fn end(self) -> RhaiResultOf { #[cfg(not(feature = "no_object"))] - return Ok(self.value); + return Ok(self._value); #[cfg(feature = "no_object")] return Err(ERR::ErrorMismatchDataType( "".into(), diff --git a/src/tests.rs b/src/tests.rs index 56871ec22..d4b3550e4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -31,10 +31,7 @@ fn check_struct_sizes() { ); #[cfg(feature = "internals")] - { - assert_eq!(size_of::(), 3 * WORD_SIZE); - assert_eq!(size_of::(), 4 * WORD_SIZE); - } + assert_eq!(size_of::(), 3 * WORD_SIZE); // The following only on 64-bit platforms diff --git a/src/tokenizer.rs b/src/tokenizer.rs index f2c380e4f..191fb6d12 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -2,7 +2,7 @@ use crate::engine::Precedence; use crate::func::native::OnParseTokenCallback; -use crate::{Engine, Identifier, LexError, Position, SmartString, INT, UNSIGNED_INT}; +use crate::{Engine, Identifier, LexError, Position, SmartString, StaticVec, INT, UNSIGNED_INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -2398,10 +2398,8 @@ pub struct MultiInputsStream<'a> { pub buf: [Option; 2], /// The current stream index. pub index: usize, - /// The first input character stream. - pub stream: Peekable>, - /// Extra input character streams. - pub extra_streams: Box<[Peekable>]>, + /// Input character streams. + pub streams: StaticVec>>, } impl InputStream for MultiInputsStream<'_> { @@ -2427,17 +2425,12 @@ impl InputStream for MultiInputsStream<'_> { } loop { - if self.index > self.extra_streams.len() { + if self.index >= self.streams.len() { // No more streams return None; } - if self.index == 0 { - if let Some(ch) = self.stream.next() { - // Next character in main stream - return Some(ch); - } - } else if let Some(ch) = self.extra_streams[self.index - 1].next() { - // Next character in current stream + if let Some(ch) = self.streams[self.index].next() { + // Next character in main stream return Some(ch); } // Jump to the next stream @@ -2452,17 +2445,12 @@ impl InputStream for MultiInputsStream<'_> { } loop { - if self.index > self.extra_streams.len() { + if self.index >= self.streams.len() { // No more streams return None; } - if self.index == 0 { - if let Some(&ch) = self.stream.peek() { - // Next character in main stream - return Some(ch); - } - } else if let Some(&ch) = self.extra_streams[self.index - 1].peek() { - // Next character in current stream + if let Some(&ch) = self.streams[self.index].peek() { + // Next character in main stream return Some(ch); } // Jump to the next stream @@ -2689,8 +2677,6 @@ pub fn lex_raw<'a>( let buffer: TokenizerControl = RefCell::new(TokenizerControlBlock::new()).into(); let buffer2 = buffer.clone(); - let mut input_streams = inputs.into_iter().map(|s| s.as_ref().chars().peekable()); - ( TokenIterator { engine, @@ -2707,8 +2693,10 @@ pub fn lex_raw<'a>( pos: Position::new(1, 0), stream: MultiInputsStream { buf: [None, None], - stream: input_streams.next().unwrap(), - extra_streams: input_streams.collect(), + streams: inputs + .into_iter() + .map(|s| s.as_ref().chars().peekable()) + .collect(), index: 0, }, token_mapper, diff --git a/src/types/custom_types.rs b/src/types/custom_types.rs index 3419fbb39..a9819a71a 100644 --- a/src/types/custom_types.rs +++ b/src/types/custom_types.rs @@ -26,7 +26,7 @@ pub struct CustomTypeInfo { /// /// Each line in non-block doc-comments starts with `///`. #[cfg(feature = "metadata")] - pub comments: Box<[crate::SmartString]>, + pub comments: crate::StaticVec, } /// _(internals)_ A collection of custom types. diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 4ffdacf43..f45f98dc0 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -400,15 +400,71 @@ impl Hash for Dynamic { Union::Blob(ref a, ..) => a.hash(state), #[cfg(not(feature = "no_object"))] Union::Map(ref m, ..) => m.hash(state), - Union::FnPtr(ref f, ..) => f.hash(state), + Union::FnPtr(ref f, ..) if f.environ.is_some() => { + unimplemented!("FnPtr with embedded environment cannot be hashed") + } + Union::FnPtr(ref f, ..) => { + f.fn_name().hash(state); + f.curry().hash(state); + } #[cfg(not(feature = "no_closure"))] Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell)).hash(state), - Union::Variant(..) => unimplemented!("{} cannot be hashed", self.type_name()), + Union::Variant(ref v, ..) => { + let _value_any = (***v).as_any(); + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } + + #[cfg(not(feature = "no_float"))] + #[cfg(not(feature = "f32_float"))] + if let Some(value) = _value_any.downcast_ref::() { + return value.to_ne_bytes().hash(state); + } + #[cfg(not(feature = "no_float"))] + #[cfg(feature = "f32_float")] + if let Some(value) = _value_any.downcast_ref::() { + return value.to_ne_bytes().hash(state); + } + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + #[cfg(not(target_family = "wasm"))] + if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } else if let Some(value) = _value_any.downcast_ref::() { + return value.hash(state); + } + + if let Some(range) = _value_any.downcast_ref::() { + return range.hash(state); + } else if let Some(range) = _value_any.downcast_ref::() { + return range.hash(state); + } + + unimplemented!("Custom type {} cannot be hashed", self.type_name()) + } #[cfg(not(feature = "no_time"))] - Union::TimeStamp(..) => unimplemented!("{} cannot be hashed", self.type_name()), + Union::TimeStamp(..) => unimplemented!("Timestamp cannot be hashed"), } } } @@ -1153,15 +1209,67 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] Union::Float(..) => true, + #[cfg(feature = "decimal")] + Union::Decimal(..) => true, #[cfg(not(feature = "no_index"))] - Union::Array(..) => true, + Union::Array(ref a, ..) => a.iter().all(Self::is_hashable), + #[cfg(not(feature = "no_index"))] + Union::Blob(..) => true, #[cfg(not(feature = "no_object"))] - Union::Map(..) => true, + Union::Map(ref m, ..) => m.values().all(Self::is_hashable), + Union::FnPtr(ref f, ..) => { + f.environ.is_none() && f.curry().iter().all(Self::is_hashable) + } + #[cfg(not(feature = "no_time"))] + Union::TimeStamp(..) => false, + + Union::Variant(ref v, ..) => { + let _value_any = (***v).as_any(); + let _type_id = _value_any.type_id(); + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + if _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + || _type_id == TypeId::of::() + { + return true; + } + + #[cfg(not(feature = "no_float"))] + #[cfg(not(feature = "f32_float"))] + if _type_id == TypeId::of::() { + return true; + } + #[cfg(not(feature = "no_float"))] + #[cfg(feature = "f32_float")] + if _type_id == TypeId::of::() { + return true; + } + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + #[cfg(not(target_family = "wasm"))] + if _type_id == TypeId::of::() || _type_id == TypeId::of::() { + return true; + } + + if _type_id == TypeId::of::() + || _type_id == TypeId::of::() + { + return true; + } + + false + } #[cfg(not(feature = "no_closure"))] Union::Shared(ref cell, ..) => crate::func::locked_read(cell).is_hashable(), - - _ => false, } } /// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is. @@ -1540,7 +1648,7 @@ impl Dynamic { pub fn flatten(self) -> Self { match self.0 { #[cfg(not(feature = "no_closure"))] - Union::Shared(cell, ..) => crate::func::shared_try_take(cell).map_or_else( + Union::Shared(cell, ..) => crate::func::native::shared_try_take(cell).map_or_else( |ref cell| crate::func::locked_read(cell).clone(), #[cfg(not(feature = "sync"))] crate::Locked::into_inner, diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 57d439254..679ee6817 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -1,7 +1,7 @@ //! The `FnPtr` type. +use crate::ast::EncapsulatedEnviron; use crate::eval::GlobalRuntimeState; -use crate::func::EncapsulatedEnviron; use crate::tokenizer::{is_reserved_keyword_or_symbol, is_valid_function_name, Token}; use crate::types::dynamic::Variant; use crate::{ @@ -13,9 +13,7 @@ use std::prelude::v1::*; use std::{ any::type_name, convert::{TryFrom, TryInto}, - fmt, - hash::{Hash, Hasher}, - mem, + fmt, mem, ops::{Index, IndexMut}, }; use thin_vec::ThinVec; @@ -28,22 +26,7 @@ pub struct FnPtr { pub(crate) curry: ThinVec, pub(crate) environ: Option>, #[cfg(not(feature = "no_function"))] - pub(crate) fn_def: Option>, -} - -impl Hash for FnPtr { - #[inline(always)] - fn hash(&self, state: &mut H) { - self.name.hash(state); - self.curry.hash(state); - - // Hash the shared [`EncapsulatedEnviron`] by hashing its shared pointer. - self.environ.as_ref().map(Shared::as_ptr).hash(state); - - // Hash the linked [`ScriptFnDef`][crate::ast::ScriptFnDef] by hashing its shared pointer. - #[cfg(not(feature = "no_function"))] - self.fn_def.as_ref().map(Shared::as_ptr).hash(state); - } + pub(crate) fn_def: Option>, } impl fmt::Display for FnPtr { @@ -486,7 +469,7 @@ impl TryFrom for FnPtr { } #[cfg(not(feature = "no_function"))] -impl>> From for FnPtr { +impl>> From for FnPtr { #[inline(always)] fn from(value: T) -> Self { let fn_def = value.into(); diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index 7ddd0db35..a735372bf 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -177,6 +177,8 @@ pub enum ParseErrorType { ModuleUndefined(String), /// Expression exceeding the maximum levels of complexity. ExprTooDeep, + /// Number of scripted functions over maximum limit. + TooManyFunctions, /// Literal exceeding the maximum size. Wrapped values are the data type name and the maximum size. LiteralTooLarge(String, usize), /// Break statement not inside a loop. @@ -246,6 +248,7 @@ impl fmt::Display for ParseErrorType { Self::WrongDocComment => f.write_str("Doc-comment must be followed immediately by a function definition"), Self::WrongExport => f.write_str("Export statement can only appear at global level"), Self::ExprTooDeep => f.write_str("Expression exceeds maximum complexity"), + Self::TooManyFunctions => f.write_str("Number of functions defined exceeds maximum limit"), Self::LoopBreak => f.write_str("Break statement should only be used inside a loop"), #[allow(deprecated)] diff --git a/src/types/scope.rs b/src/types/scope.rs index 16bc229bb..e8622eaa8 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -1,7 +1,7 @@ //! Module that defines the [`Scope`] type representing a function call-stack scope. use super::dynamic::{AccessMode, Variant}; -use crate::{Dynamic, Identifier, ImmutableString}; +use crate::{Dynamic, Identifier, ImmutableString, StaticVec}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -69,7 +69,7 @@ pub struct Scope<'a> { /// /// This `Vec` is not filled until needed because aliases are used rarely /// (only for `export` statements). - aliases: ThinVec>, + aliases: ThinVec>, /// Phantom to keep the lifetime parameter in order not to break existing code. dummy: PhantomData<&'a ()>, } @@ -819,10 +819,8 @@ impl Scope<'_> { self.aliases.resize(index + 1, <_>::default()); } let aliases = self.aliases.get_mut(index).unwrap(); - if aliases.is_empty() || !aliases.contains(&alias) { - let mut vec = std::mem::take(aliases).to_vec(); - vec.push(alias); - *aliases = vec.into_boxed_slice(); + if !aliases.contains(&alias) { + aliases.push(alias); } self } diff --git a/tests/functions.rs b/tests/functions.rs index 31f500574..8089abf93 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "no_function"))] -use rhai::{Dynamic, Engine, EvalAltResult, FnNamespace, Module, NativeCallContext, ParseErrorType, Shared, INT}; +use rhai::{Dynamic, Engine, EvalAltResult, FnNamespace, FuncRegistration, Module, NativeCallContext, ParseErrorType, Shared, INT}; #[test] fn test_functions() { @@ -84,8 +84,9 @@ fn test_functions_namespaces() { #[cfg(not(feature = "no_module"))] { let mut m = Module::new(); - let hash = m.set_native_fn("test", || Ok(999 as INT)); - m.update_fn_namespace(hash, FnNamespace::Global); + + let f = || 999 as INT; + FuncRegistration::new("test").with_namespace(FnNamespace::Global).set_into_module(&mut m, f); engine.register_static_module("hello", m.into()); @@ -537,3 +538,39 @@ fn test_functions_is_def() { ) .unwrap()); } + +#[test] +#[cfg(not(feature = "unchecked"))] +fn test_functions_max() { + let mut engine = Engine::new(); + engine.set_max_functions(5); + + engine + .compile( + " + fn foo1() {} + fn foo2() {} + fn foo3() {} + fn foo4() {} + fn foo5() {} + ", + ) + .unwrap(); + + assert!(matches!( + engine + .compile( + " + fn foo1() {} + fn foo2() {} + fn foo3() {} + fn foo4() {} + fn foo5() {} + fn foo6() {} + " + ) + .expect_err("should err") + .err_type(), + ParseErrorType::TooManyFunctions + )) +} diff --git a/tests/modules.rs b/tests/modules.rs index bf2dabfae..c06bf14c4 100644 --- a/tests/modules.rs +++ b/tests/modules.rs @@ -1,7 +1,7 @@ #![cfg(not(feature = "no_module"))] use rhai::{ module_resolvers::{DummyModuleResolver, StaticModuleResolver}, - Dynamic, Engine, EvalAltResult, FnNamespace, ImmutableString, Module, ParseError, ParseErrorType, Scope, INT, + Dynamic, Engine, EvalAltResult, FnNamespace, FuncRegistration, ImmutableString, Module, ParseError, ParseErrorType, Scope, INT, }; // #[cfg(all(not(feature = "no_function"), feature = "internals"))] @@ -36,8 +36,9 @@ fn test_module_sub_module() { sub_module2.build_index(); assert!(!sub_module2.contains_indexed_global_functions()); - let super_hash = sub_module2.set_native_fn("super_inc", |x: &mut INT| Ok(*x + 1)); - sub_module2.update_fn_namespace(super_hash, FnNamespace::Global); + let f = |x: &mut INT| *x + 1; + FuncRegistration::new("super_inc").with_namespace(FnNamespace::Global).set_into_module(&mut sub_module2, f); + sub_module2.build_index(); assert!(sub_module2.contains_indexed_global_functions()); @@ -90,11 +91,9 @@ fn test_module_resolver() { module.set_var("answer", 42 as INT); module.set_native_fn("sum", |x: INT, y: INT, z: INT, w: INT| Ok(x + y + z + w)); - let double_hash = module.set_native_fn("double", |x: &mut INT| { - *x *= 2; - Ok(()) - }); - module.update_fn_namespace(double_hash, FnNamespace::Global); + + let f = |x: &mut INT| *x *= 2; + FuncRegistration::new("double").with_namespace(FnNamespace::Global).set_into_module(&mut module, f); #[cfg(not(feature = "no_float"))] module.set_native_fn("sum_of_three_args", |target: &mut INT, a: INT, b: INT, c: rhai::FLOAT| { diff --git a/tests/switch.rs b/tests/switch.rs index e9be2bb62..94915713c 100644 --- a/tests/switch.rs +++ b/tests/switch.rs @@ -56,6 +56,7 @@ fn test_switch() { .unwrap(), 3 ); + assert_eq!(engine.eval::("let x = 1..42; switch x { 1 => (), 2 => 'a', 1..42 => true }").unwrap(), true); assert_eq!(engine.eval_with_scope::(&mut scope, "switch 42 { 42 => 123, 42 => 999 }").unwrap(), 123);