diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06631443..cfca586f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: os: [ubuntu-latest] flags: - "" - - "--features metadata,internals" + - "--features metadata,serde,internals" - "--features unchecked" - "--features sync" - "--features no_optimize" @@ -34,7 +34,7 @@ jobs: - "--features no_module" - "--features no_closure" - "--features unicode-xid-ident" - - "--features sync,no_function,no_float,no_optimize,no_module,no_closure,metadata,unchecked" + - "--features sync,no_function,no_float,no_optimize,no_module,no_closure,metadata,serde,unchecked" toolchain: [stable] experimental: [false] include: diff --git a/CHANGELOG.md b/CHANGELOG.md index ad8a65cf..91efdb6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,31 +4,37 @@ Rhai Release Notes Version 0.19.15 =============== -This version replaces internal usage of `HashMap` with `BTreeMap` in many cases, which should result -in speed improvements because a `BTreeMap` is faster when the number of items held is small. +This version replaces all internal usage of `HashMap` with `BTreeMap`, which should result +in some speed improvement because a `BTreeMap` is leaner when the number of items held is small. +Most, if not all, collections in Rhai hold very few data items, so this is a typical scenario of +many tiny-sized collections. -This also translates to the Rhai object map type, `Map`, which used to be an alias to `HashMap` and -is now aliased to `BTreeMap` instead. This change is due to the fact that, in the vast majority of -object map usages, the number of properties held is small. +The Rhai object map type, `Map`, used to be an alias to `HashMap` and is now aliased to `BTreeMap` +instead. This is also because, in the vast majority of usage cases, the number of properties held by +an object map is small. -`HashMap` and `BTreeMap` have almost identical public API's so this change is unlikely to break a -lot of existing code. +`HashMap` and `BTreeMap` have almost identical public API's so this change is unlikely to break +existing code. + +All function signature/metadata methods are now grouped under the umbrella `metadata` feature. Breaking changes ---------------- -* `Map` is now an alias to `BTreeMap` instead of `HashMap`. This is because most object maps used have few properties. +* `Map` is now an alias to `BTreeMap` instead of `HashMap` because most object maps hold few properties. * The traits `RegisterFn` and `RegisterResultFn` are removed. `Engine::register_fn` and `Engine::register_result_fn` are now implemented directly on `Engine`. * `FnPtr::call_dynamic` now takes `&NativeCallContext` instead of consuming it. * All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`. * `Array::reduce` and `Array::reduce_rev` now take a `Dynamic` as initial value instead of a function pointer. * `protected`, `super` are now reserved keywords. +* The `Module::set_fn_XXX` API now take `&str` as the function name instead of `Into`. +* The _reflections_ API such as `Engine::gen_fn_signatures`, `Module::update_fn_metadata` etc. are put under the `metadata` feature gate. Enhancements ------------ -* Replaced most `HashMap` usage with `BTreeMap` for better performance when the number of items is small. +* Replaced all `HashMap` usage with `BTreeMap` for better performance because collections in Rhai are tiny. * `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any clonable type. * `#[rhai_fn(return_raw)]` can now return `Result>` where `T` is any clonable type instead of `Result>`. diff --git a/Cargo.toml b/Cargo.toml index 849e2e1e..b7ecc4f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ no_closure = [] # no automatic sharing and capture of anonymous no_module = [] # no modules internals = [] # expose internal data structures unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers. -metadata = ["serde", "serde_json"] # enables exporting functions metadata to JSON +metadata = ["serde_json"] # enable exporting functions metadata no_std = ["smallvec/union", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] @@ -92,4 +92,4 @@ instant = { version = "0.1" } # WASM implementation of std::time::Instant instant = { version = "0.1" } # WASM implementation of std::time::Instant [package.metadata.docs.rs] -features = ["metadata", "internals", "decimal"] # compiling for no-std +features = ["metadata", "serde", "internals", "decimal"] # compiling for no-std diff --git a/codegen/src/function.rs b/codegen/src/function.rs index e98785e7..03d42400 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -300,55 +300,50 @@ impl Parse for ExportedFn { let visibility = fn_all.vis; // Determine if the function requires a call context - if let Some(first_arg) = fn_all.sig.inputs.first() { - if let syn::FnArg::Typed(syn::PatType { ref ty, .. }) = first_arg { + match fn_all.sig.inputs.first() { + Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) => { match flatten_type_groups(ty.as_ref()) { syn::Type::Path(p) if p.path == context_type_path1 || p.path == context_type_path2 => { pass_context = true; } - _ => (), + _ => {} } } + _ => {} } let skip_slots = if pass_context { 1 } else { 0 }; // Determine whether function generates a special calling convention for a mutable receiver. - let mut_receiver = { - if let Some(first_arg) = fn_all.sig.inputs.iter().skip(skip_slots).next() { - match first_arg { - syn::FnArg::Receiver(syn::Receiver { - reference: Some(_), .. + let mut_receiver = match fn_all.sig.inputs.iter().skip(skip_slots).next() { + Some(syn::FnArg::Receiver(syn::Receiver { + reference: Some(_), .. + })) => true, + Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) => { + match flatten_type_groups(ty.as_ref()) { + syn::Type::Reference(syn::TypeReference { + mutability: Some(_), + .. }) => true, - syn::FnArg::Typed(syn::PatType { ref ty, .. }) => { - match flatten_type_groups(ty.as_ref()) { - syn::Type::Reference(syn::TypeReference { - mutability: Some(_), - .. - }) => true, - 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 => false, - _ => { - return Err(syn::Error::new( - ty.span(), - "references from Rhai in this position must be mutable", - )) - } - }, - _ => false, + 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 => false, + _ => { + return Err(syn::Error::new( + ty.span(), + "references from Rhai in this position must be mutable", + )) } - } + }, _ => false, } - } else { - false } + _ => false, }; // All arguments after the first must be moved except for &str. @@ -381,22 +376,25 @@ impl Parse for ExportedFn { } // Check return type. - if let syn::ReturnType::Type(_, ref ret_type) = fn_all.sig.output { - match flatten_type_groups(ret_type.as_ref()) { - syn::Type::Ptr(_) => { - return Err(syn::Error::new( - fn_all.sig.output.span(), - "Rhai functions cannot return pointers", - )) + match fn_all.sig.output { + syn::ReturnType::Type(_, ref ret_type) => { + match flatten_type_groups(ret_type.as_ref()) { + syn::Type::Ptr(_) => { + return Err(syn::Error::new( + fn_all.sig.output.span(), + "Rhai functions cannot return pointers", + )) + } + syn::Type::Reference(_) => { + return Err(syn::Error::new( + fn_all.sig.output.span(), + "Rhai functions cannot return references", + )) + } + _ => {} } - syn::Type::Reference(_) => { - return Err(syn::Error::new( - fn_all.sig.output.span(), - "Rhai functions cannot return references", - )) - } - _ => {} } + _ => {} } Ok(ExportedFn { entire_span, @@ -494,10 +492,9 @@ impl ExportedFn { } pub fn return_type(&self) -> Option<&syn::Type> { - if let syn::ReturnType::Type(_, ref ret_type) = self.signature.output { - Some(flatten_type_groups(ret_type)) - } else { - None + match self.signature.output { + syn::ReturnType::Type(_, ref ret_type) => Some(flatten_type_groups(ret_type)), + _ => None, } } @@ -590,20 +587,14 @@ impl ExportedFn { let name: syn::Ident = syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span()); let impl_block = self.generate_impl("Token"); - let callable_block = self.generate_callable("Token"); - let param_names_block = self.generate_param_names("Token"); - let input_types_block = self.generate_input_types("Token"); let dyn_result_fn_block = self.generate_dynamic_fn(); let vis = self.visibility; quote! { #[automatically_derived] #vis mod #name { use super::*; - struct Token(); + pub struct Token(); #impl_block - #callable_block - #param_names_block - #input_types_block #dyn_result_fn_block } } @@ -616,22 +607,18 @@ impl ExportedFn { dynamic_signature.ident = syn::Ident::new("dynamic_result_fn", proc_macro2::Span::call_site()); dynamic_signature.output = syn::parse2::(quote! { - -> Result> + -> RhaiResult }) .unwrap(); let arguments: Vec = dynamic_signature .inputs .iter() - .filter_map(|fn_arg| { - if let syn::FnArg::Typed(syn::PatType { ref pat, .. }) = fn_arg { - if let syn::Pat::Ident(ref ident) = pat.as_ref() { - Some(ident.ident.clone()) - } else { - None - } - } else { - None - } + .filter_map(|fn_arg| match fn_arg { + syn::FnArg::Typed(syn::PatType { ref pat, .. }) => match pat.as_ref() { + syn::Pat::Ident(ref ident) => Some(ident.ident.clone()), + _ => None, + }, + _ => None, }) .collect(); @@ -656,48 +643,6 @@ impl ExportedFn { } } - pub fn generate_callable(&self, on_type_name: &str) -> proc_macro2::TokenStream { - let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); - let callable_fn_name: syn::Ident = syn::Ident::new( - &format!("{}_callable", on_type_name.to_lowercase()), - self.name().span(), - ); - quote! { - #[inline(always)] - pub fn #callable_fn_name() -> CallableFunction { - #token_name().into() - } - } - } - - pub fn generate_param_names(&self, on_type_name: &str) -> proc_macro2::TokenStream { - let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); - let param_names_fn_name: syn::Ident = syn::Ident::new( - &format!("{}_param_names", on_type_name.to_lowercase()), - self.name().span(), - ); - quote! { - #[inline(always)] - pub fn #param_names_fn_name() -> Box<[&'static str]> { - #token_name().param_names() - } - } - } - - pub fn generate_input_types(&self, on_type_name: &str) -> proc_macro2::TokenStream { - let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); - let input_types_fn_name: syn::Ident = syn::Ident::new( - &format!("{}_input_types", on_type_name.to_lowercase()), - self.name().span(), - ); - quote! { - #[inline(always)] - pub fn #input_types_fn_name() -> Box<[TypeId]> { - #token_name().input_types() - } - } - } - pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream { let sig_name = self.name().clone(); let arg_count = self.arg_count(); @@ -873,23 +818,19 @@ impl ExportedFn { let type_name = syn::Ident::new(on_type_name, proc_macro2::Span::call_site()); quote! { + impl #type_name { + pub const PARAM_NAMES: &'static [&'static str] = &[#(#input_type_names,)* #return_type]; + #[inline(always)] pub fn param_types() -> [TypeId; #arg_count] { [#(#input_type_exprs),*] } + } impl PluginFunction for #type_name { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), #arg_count, "wrong arg count: {} != {}", args.len(), #arg_count); #(#unpack_statements)* #return_expr } #[inline(always)] fn is_method_call(&self) -> bool { #is_method_call } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(#type_name()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec![#(#input_type_names,)* #return_type].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![#(#input_type_exprs),*].into_boxed_slice() - } } } } diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index a8bc11e8..e6af8fe2 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -212,10 +212,9 @@ pub fn export_module( #[proc_macro] pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream { let module_path = parse_macro_input!(module_path as syn::Path); - let tokens = quote::quote! { + proc_macro::TokenStream::from(quote::quote! { #module_path::rhai_module_generate() - }; - proc_macro::TokenStream::from(tokens) + }) } /// Macro to combine a _plugin module_ into an existing module. @@ -258,15 +257,12 @@ pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::Toke /// ``` #[proc_macro] pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (module_expr, _export_name, module_path) = match crate::register::parse_register_macro(args) - { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let tokens = quote! { - #module_path::rhai_generate_into_module(#module_expr, true); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! { + #module_path::rhai_generate_into_module(#module_expr, true); + }), + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ (defined via [`#[export_fn]`][export_fn]) into an `Engine`. @@ -293,16 +289,15 @@ pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro /// ``` #[proc_macro] pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (engine_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #engine_expr.register_result_fn(&(#export_name), #gen_mod_path::dynamic_result_fn); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((engine_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #engine_expr.register_result_fn(#export_name, #gen_mod_path::dynamic_result_fn); + }) + } + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ into a Rhai `Module`. @@ -332,19 +327,18 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS /// ``` #[proc_macro] pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (module_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, - Some(#gen_mod_path::token_param_names().as_ref()), - #gen_mod_path::token_input_types().as_ref(), - #gen_mod_path::token_callable()); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, + Some(#gen_mod_path::Token::PARAM_NAMES), + &#gen_mod_path::Token::param_types(), + #gen_mod_path::Token().into()); + }) + } + Err(e) => e.to_compile_error().into(), + } } /// Macro to register a _plugin function_ into a Rhai `Module` and expose it globally. @@ -374,17 +368,16 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream /// ``` #[proc_macro] pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { - let (module_expr, export_name, rust_mod_path) = - match crate::register::parse_register_macro(args) { - Ok(triple) => triple, - Err(e) => return e.to_compile_error().into(), - }; - let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); - let tokens = quote! { - #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, - Some(#gen_mod_path::token_param_names().as_ref()), - #gen_mod_path::token_input_types().as_ref(), - #gen_mod_path::token_callable()); - }; - proc_macro::TokenStream::from(tokens) + match crate::register::parse_register_macro(args) { + Ok((module_expr, export_name, rust_mod_path)) => { + let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); + proc_macro::TokenStream::from(quote! { + #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, + Some(#gen_mod_path::Token::PARAM_NAMES), + &#gen_mod_path::Token::param_types(), + #gen_mod_path::Token().into()); + }) + } + Err(e) => e.to_compile_error().into(), + } } diff --git a/codegen/src/module.rs b/codegen/src/module.rs index ca740de1..df065797 100644 --- a/codegen/src/module.rs +++ b/codegen/src/module.rs @@ -156,8 +156,11 @@ impl Parse for Module { }) => { // #[cfg] attributes are not allowed on const declarations crate::attrs::deny_cfg_attr(&attrs)?; - if let syn::Visibility::Public(_) = vis { - consts.push((ident.to_string(), ty.clone(), expr.as_ref().clone())); + match vis { + syn::Visibility::Public(_) => { + consts.push((ident.to_string(), ty.clone(), expr.as_ref().clone())) + } + _ => {} } } _ => {} @@ -170,26 +173,23 @@ impl Parse for Module { sub_modules.reserve(content.len() - fns.len() - consts.len()); let mut i = 0; while i < content.len() { - if let syn::Item::Mod(_) = &content[i] { - let mut item_mod = match content.remove(i) { - syn::Item::Mod(m) => m, - _ => unreachable!(), - }; - let params: ExportedModParams = match crate::attrs::inner_item_attributes( - &mut item_mod.attrs, - "rhai_mod", - ) { - Ok(p) => p, - Err(e) => return Err(e), - }; - let module = - syn::parse2::(item_mod.to_token_stream()).and_then(|mut m| { - m.set_params(params)?; - Ok(m) - })?; - sub_modules.push(module); - } else { - i += 1; + match content[i] { + syn::Item::Mod(_) => { + let mut item_mod = match content.remove(i) { + syn::Item::Mod(m) => m, + _ => unreachable!(), + }; + let params: ExportedModParams = + crate::attrs::inner_item_attributes(&mut item_mod.attrs, "rhai_mod")?; + let module = syn::parse2::(item_mod.to_token_stream()).and_then( + |mut m| { + m.set_params(params)?; + Ok(m) + }, + )?; + sub_modules.push(module); + } + _ => i += 1, } } } else { diff --git a/codegen/src/register.rs b/codegen/src/register.rs index 8ea91fd3..5813e2c1 100644 --- a/codegen/src/register.rs +++ b/codegen/src/register.rs @@ -33,8 +33,7 @@ pub fn parse_register_macro( )); } let export_name = match &items[1] { - syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => - #lit_str.to_string()), + syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => #lit_str), expr => quote! { #expr }, }; let rust_mod_path = if let syn::Expr::Path(ref path) = &items[2] { diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index b1eb1947..11c8d1de 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use quote::{quote, ToTokens}; +use quote::quote; use crate::attrs::ExportScope; use crate::function::{ @@ -81,16 +81,6 @@ pub fn generate_body( ); let reg_names = function.exported_names(); - let fn_input_names: Vec = function - .arg_list() - .map(|fn_arg| match fn_arg { - syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"), - syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { - format!("{}: {}", pat.to_token_stream(), print_type(ty)) - } - }) - .collect(); - let fn_input_types: Vec = function .arg_list() .map(|fn_arg| match fn_arg { @@ -128,17 +118,12 @@ pub fn generate_body( }; syn::parse2::(quote! { - core::any::TypeId::of::<#arg_type>()}) + TypeId::of::<#arg_type>()}) .unwrap() } }) .collect(); - let return_type = function - .return_type() - .map(print_type) - .unwrap_or_else(|| "()".to_string()); - for fn_literal in reg_names { let mut namespace = FnNamespaceAccess::Internal; @@ -172,7 +157,7 @@ pub fn generate_body( set_fn_statements.push( syn::parse2::(quote! { m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, - Some(&[#(#fn_input_names,)* #return_type]), &[#(#fn_input_types),*], + Some(#fn_token_name::PARAM_NAMES), &[#(#fn_input_types),*], #fn_token_name().into()); }) .unwrap(), @@ -181,12 +166,9 @@ pub fn generate_body( gen_fn_tokens.push(quote! { #[allow(non_camel_case_types)] - struct #fn_token_name(); + pub struct #fn_token_name(); }); gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string())); - gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string())); - gen_fn_tokens.push(function.generate_param_names(&fn_token_name.to_string())); - gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string())); } let mut generate_fn_call = syn::parse2::(quote! { diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index c0abce5b..a8a56d83 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -275,35 +275,21 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_do_nothing { use super::*; - struct Token(); + pub struct Token(); + impl Token { + pub const PARAM_NAMES: &'static [&'static str] = &["()"]; + #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } + } impl PluginFunction for Token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 0usize, - "wrong arg count: {} != {}", args.len(), 0usize); Ok(Dynamic::from(do_nothing())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn() -> Result > { + #[inline(always)] pub fn dynamic_result_fn() -> RhaiResult { Ok(Dynamic::from(do_nothing())) } } @@ -323,37 +309,23 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_do_something { use super::*; - struct Token(); + pub struct Token(); + impl Token { + pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; + #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } + } impl PluginFunction for Token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn(x: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: usize) -> RhaiResult { Ok(Dynamic::from(do_something(x))) } } @@ -373,37 +345,23 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_do_something { use super::*; - struct Token(); + pub struct Token(); + impl Token { + pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; + #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } + } impl PluginFunction for Token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(context, arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> RhaiResult { Ok(Dynamic::from(do_something(context, x))) } } @@ -426,36 +384,22 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_return_dynamic { use super::*; - struct Token(); + pub struct Token(); + impl Token { + pub const PARAM_NAMES: &'static [&'static str] = &["rhai::Dynamic"]; + #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } + } impl PluginFunction for Token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 0usize, - "wrong arg count: {} != {}", args.len(), 0usize); Ok(Dynamic::from(return_dynamic())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["rhai::Dynamic"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn() -> Result > { + #[inline(always)] pub fn dynamic_result_fn() -> RhaiResult { Ok(Dynamic::from(return_dynamic())) } } @@ -472,25 +416,20 @@ mod generate_tests { }; let expected_tokens = quote! { + impl TestStruct { + pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; + #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } + } impl PluginFunction for TestStruct { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(TestStruct()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } + } }; let item_fn = syn::parse2::(input_tokens).unwrap(); @@ -507,12 +446,14 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_add_together { use super::*; - struct Token(); + pub struct Token(); + impl Token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) @@ -520,26 +461,9 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize", "y: usize", "usize"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn(x: usize, y: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: usize, y: usize) -> RhaiResult { Ok(Dynamic::from(add_together(x, y))) } } @@ -559,12 +483,14 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_increment { use super::*; - struct Token(); + pub struct Token(); + impl Token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -577,26 +503,9 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut usize", "y: usize", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: &mut usize, y: usize) -> RhaiResult { Ok(Dynamic::from(increment(x, y))) } } @@ -617,37 +526,23 @@ mod generate_tests { #[automatically_derived] pub mod rhai_fn_special_print { use super::*; - struct Token(); + pub struct Token(); + impl Token { + pub const PARAM_NAMES: &'static [&'static str] = &["message: &str", "()"]; + #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } + } impl PluginFunction for Token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(special_print(&arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { Box::new(Token()) } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["message: &str", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn token_callable() -> CallableFunction { - Token().into() - } - #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { - Token().param_names() - } - #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { - Token().input_types() } #[allow(unused)] - #[inline(always)] pub fn dynamic_result_fn(message: &str) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(message: &str) -> RhaiResult { Ok(Dynamic::from(special_print(message))) } } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 61645c81..fdf4cf12 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -297,40 +297,25 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&["INT"]), &[], + m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, + Some(get_mystic_number_token::PARAM_NAMES), &[], get_mystic_number_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct get_mystic_number_token(); + pub struct get_mystic_number_token(); + impl get_mystic_number_token { + pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; + #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } + } impl PluginFunction for get_mystic_number_token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 0usize, - "wrong arg count: {} != {}", args.len(), 0usize); Ok(Dynamic::from(get_mystic_number())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(get_mystic_number_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![].into_boxed_slice() - } - } - #[inline(always)] pub fn get_mystic_number_token_callable() -> CallableFunction { - get_mystic_number_token().into() - } - #[inline(always)] pub fn get_mystic_number_token_param_names() -> Box<[&'static str]> { - get_mystic_number_token().param_names() - } - #[inline(always)] pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { - get_mystic_number_token().input_types() } } }; @@ -366,42 +351,26 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT", "INT"]), - &[core::any::TypeId::of::()], + m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, + Some(add_one_to_token::PARAM_NAMES), &[TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct add_one_to_token(); + pub struct add_one_to_token(); + impl add_one_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_one_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { - add_one_to_token().into() - } - #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { - add_one_to_token().param_names() - } - #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { - add_one_to_token().input_types() } } }; @@ -436,42 +405,26 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "INT"]), - &[core::any::TypeId::of::()], + m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(add_one_to_token::PARAM_NAMES), + &[TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct add_one_to_token(); + pub struct add_one_to_token(); + impl add_one_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_one_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { - add_one_to_token().into() - } - #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { - add_one_to_token().param_names() - } - #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { - add_one_to_token().input_types() } } }; @@ -517,54 +470,40 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "INT"]), - &[core::any::TypeId::of::()], + 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(&["x: INT", "y: INT", "INT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct add_one_to_token(); + pub struct add_one_to_token(); + impl add_one_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_one_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { - add_one_to_token().into() - } - #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { - add_one_to_token().param_names() - } - #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { - add_one_to_token().input_types() } #[allow(non_camel_case_types)] - struct add_n_to_token(); + pub struct add_n_to_token(); + impl add_n_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_n_to(arg0, arg1))) @@ -572,25 +511,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_n_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_n_to_token_callable() -> CallableFunction { - add_n_to_token().into() - } - #[inline(always)] pub fn add_n_to_token_param_names() -> Box<[&'static str]> { - add_n_to_token().param_names() - } - #[inline(always)] pub fn add_n_to_token_input_types() -> Box<[TypeId]> { - add_n_to_token().input_types() } } }; @@ -625,18 +545,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), + &[TypeId::of::(), TypeId::of::()], add_together_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct add_together_token(); + pub struct add_together_token(); + impl add_together_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) @@ -644,25 +566,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_together_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_together_token_callable() -> CallableFunction { - add_together_token().into() - } - #[inline(always)] pub fn add_together_token_param_names() -> Box<[&'static str]> { - add_together_token().param_names() - } - #[inline(always)] pub fn add_together_token_input_types() -> Box<[TypeId]> { - add_together_token().input_types() } } }; @@ -698,24 +601,26 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT", "INT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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(&["x: INT", "y: INT", "INT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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(&["x: INT", "y: INT", "INT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(add_together_token::PARAM_NAMES), + &[TypeId::of::(), TypeId::of::()], add_together_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct add_together_token(); + pub struct add_together_token(); + impl add_together_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) @@ -723,25 +628,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(add_together_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn add_together_token_callable() -> CallableFunction { - add_together_token().into() - } - #[inline(always)] pub fn add_together_token_param_names() -> Box<[&'static str]> { - add_together_token().param_names() - } - #[inline(always)] pub fn add_together_token_input_types() -> Box<[TypeId]> { - add_together_token().input_types() } } }; @@ -958,40 +844,25 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&["INT"]), &[], + m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, + Some(get_mystic_number_token::PARAM_NAMES), &[], get_mystic_number_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct get_mystic_number_token(); + pub struct get_mystic_number_token(); + impl get_mystic_number_token { + pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; + #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } + } impl PluginFunction for get_mystic_number_token { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 0usize, - "wrong arg count: {} != {}", args.len(), 0usize); Ok(Dynamic::from(get_mystic_number())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(get_mystic_number_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["INT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![].into_boxed_slice() - } - } - #[inline(always)] pub fn get_mystic_number_token_callable() -> CallableFunction { - get_mystic_number_token().into() - } - #[inline(always)] pub fn get_mystic_number_token_param_names() -> Box<[&'static str]> { - get_mystic_number_token().param_names() - } - #[inline(always)] pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { - get_mystic_number_token().input_types() } } }; @@ -1057,42 +928,26 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: &str", "()"]), - &[core::any::TypeId::of::()], + m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(print_out_to_token::PARAM_NAMES), + &[TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct print_out_to_token(); + pub struct print_out_to_token(); + impl print_out_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(print_out_to(&arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(print_out_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &str", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn print_out_to_token_callable() -> CallableFunction { - print_out_to_token().into() - } - #[inline(always)] pub fn print_out_to_token_param_names() -> Box<[&'static str]> { - print_out_to_token().param_names() - } - #[inline(always)] pub fn print_out_to_token_input_types() -> Box<[TypeId]> { - print_out_to_token().input_types() } } }; @@ -1127,42 +982,26 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: String", "()"]), - &[core::any::TypeId::of::()], + m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, Some(print_out_to_token::PARAM_NAMES), + &[TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct print_out_to_token(); + pub struct print_out_to_token(); + impl print_out_to_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); let arg0 = mem::take(args[0usize]).take_string().unwrap(); Ok(Dynamic::from(print_out_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(print_out_to_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: String", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn print_out_to_token_callable() -> CallableFunction { - print_out_to_token().into() - } - #[inline(always)] pub fn print_out_to_token_param_names() -> Box<[&'static str]> { - print_out_to_token().param_names() - } - #[inline(always)] pub fn print_out_to_token_input_types() -> Box<[TypeId]> { - print_out_to_token().input_types() } } }; @@ -1198,18 +1037,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("foo", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut FLOAT", "y: INT", "FLOAT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + m.set_fn("foo", FnNamespace::Internal, FnAccess::Public, Some(foo_token::PARAM_NAMES), + &[TypeId::of::(), TypeId::of::()], foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct foo_token(); + pub struct foo_token(); + impl foo_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(foo(arg0, arg1))) @@ -1217,24 +1058,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(foo_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT", "y: INT", "FLOAT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn foo_token_callable() -> CallableFunction { - foo_token().into() - } - #[inline(always)] pub fn foo_token_param_names() -> Box<[&'static str]> { - foo_token().param_names() - } - #[inline(always)] pub fn foo_token_input_types() -> Box<[TypeId]> { - foo_token().input_types() } } }; @@ -1269,18 +1092,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut FLOAT", "()"]), - &[core::any::TypeId::of::()], + m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), + &[TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct increment_token(); + pub struct increment_token(); + impl increment_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1292,24 +1117,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(increment_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn increment_token_callable() -> CallableFunction { - increment_token().into() - } - #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { - increment_token().param_names() - } - #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { - increment_token().input_types() } } }; @@ -1347,18 +1154,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut FLOAT", "()"]), - &[core::any::TypeId::of::()], + m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), + &[TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct increment_token(); + pub struct increment_token(); + impl increment_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1370,24 +1179,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(increment_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn increment_token_callable() -> CallableFunction { - increment_token().into() - } - #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { - increment_token().param_names() - } - #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { - increment_token().input_types() } } #[allow(unused_imports)] @@ -1446,18 +1237,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut FLOAT", "()"]), - &[core::any::TypeId::of::()], + m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, Some(increment_token::PARAM_NAMES), + &[TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct increment_token(); + pub struct increment_token(); + impl increment_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1469,24 +1262,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(increment_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn increment_token_callable() -> CallableFunction { - increment_token().into() - } - #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { - increment_token().param_names() - } - #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { - increment_token().input_types() } } #[allow(unused_imports)] @@ -1544,18 +1319,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "u64"]), - &[core::any::TypeId::of::()], + m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), + &[TypeId::of::()], int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct int_foo_token(); + pub struct int_foo_token(); + impl int_foo_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1567,24 +1344,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(int_foo_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "u64"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { - int_foo_token().into() - } - #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { - int_foo_token().param_names() - } - #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { - int_foo_token().input_types() } } }; @@ -1620,21 +1379,23 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "u64"]), - &[core::any::TypeId::of::()], + 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(&["x: &mut u64", "u64"]), - &[core::any::TypeId::of::()], + m.set_fn("get$square", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), + &[TypeId::of::()], int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct int_foo_token(); + pub struct int_foo_token(); + impl int_foo_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 1usize, - "wrong arg count: {} != {}", args.len(), 1usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1646,24 +1407,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(int_foo_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "u64"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { - int_foo_token().into() - } - #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { - int_foo_token().param_names() - } - #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { - int_foo_token().input_types() } } }; @@ -1699,18 +1442,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), + &[TypeId::of::(), TypeId::of::()], int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct int_foo_token(); + pub struct int_foo_token(); + impl int_foo_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1723,24 +1468,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(int_foo_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "y: u64", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { - int_foo_token().into() - } - #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { - int_foo_token().param_names() - } - #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { - int_foo_token().input_types() } } }; @@ -1776,21 +1503,23 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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(&["x: &mut u64", "y: u64", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + m.set_fn("set$squared", FnNamespace::Global, FnAccess::Public, Some(int_foo_token::PARAM_NAMES), + &[TypeId::of::(), TypeId::of::()], int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct int_foo_token(); + pub struct int_foo_token(); + impl int_foo_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1803,24 +1532,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(int_foo_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "y: u64", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { - int_foo_token().into() - } - #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { - int_foo_token().param_names() - } - #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { - int_foo_token().input_types() } } }; @@ -1856,18 +1567,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$get$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct get_by_index_token(); + pub struct get_by_index_token(); + impl get_by_index_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1880,25 +1593,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(get_by_index_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "FLOAT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn get_by_index_token_callable() -> CallableFunction { - get_by_index_token().into() - } - #[inline(always)] pub fn get_by_index_token_param_names() -> Box<[&'static str]> { - get_by_index_token().param_names() - } - #[inline(always)] pub fn get_by_index_token_input_types() -> Box<[TypeId]> { - get_by_index_token().input_types() } } }; @@ -1934,21 +1628,23 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("get", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "FLOAT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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(&["x: &mut MyCollection", "i: u64", "FLOAT"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::()], + 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()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct get_by_index_token(); + pub struct get_by_index_token(); + impl get_by_index_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 2usize, - "wrong arg count: {} != {}", args.len(), 2usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -1961,25 +1657,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(get_by_index_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "FLOAT"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn get_by_index_token_callable() -> CallableFunction { - get_by_index_token().into() - } - #[inline(always)] pub fn get_by_index_token_param_names() -> Box<[&'static str]> { - get_by_index_token().param_names() - } - #[inline(always)] pub fn get_by_index_token_input_types() -> Box<[TypeId]> { - get_by_index_token().input_types() } } }; @@ -2015,18 +1692,20 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("index$set$", FnNamespace::Global, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], + 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()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct set_by_index_token(); + pub struct set_by_index_token(); + impl set_by_index_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 3usize, - "wrong arg count: {} != {}", args.len(), 3usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -2040,26 +1719,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(set_by_index_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn set_by_index_token_callable() -> CallableFunction { - set_by_index_token().into() - } - #[inline(always)] pub fn set_by_index_token_param_names() -> Box<[&'static str]> { - set_by_index_token().param_names() - } - #[inline(always)] pub fn set_by_index_token_input_types() -> Box<[TypeId]> { - set_by_index_token().input_types() } } }; @@ -2095,21 +1754,23 @@ mod generate_tests { } #[allow(unused_mut)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { - m.set_fn("set", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], + 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(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), - &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], + 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()); if flatten {} else {} } #[allow(non_camel_case_types)] - struct set_by_index_token(); + pub struct set_by_index_token(); + impl set_by_index_token { + 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 { #[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { - debug_assert_eq!(args.len(), 3usize, - "wrong arg count: {} != {}", args.len(), 3usize); if args[0usize].is_read_only() { return Err(Box::new( EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) @@ -2123,26 +1784,6 @@ mod generate_tests { #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_variadic(&self) -> bool { false } - #[inline(always)] fn clone_boxed(&self) -> Box { - Box::new(set_by_index_token()) - } - #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"].into_boxed_slice() - } - #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { - new_vec![TypeId::of::(), - TypeId::of::(), - TypeId::of::()].into_boxed_slice() - } - } - #[inline(always)] pub fn set_by_index_token_callable() -> CallableFunction { - set_by_index_token().into() - } - #[inline(always)] pub fn set_by_index_token_param_names() -> Box<[&'static str]> { - set_by_index_token().param_names() - } - #[inline(always)] pub fn set_by_index_token_input_types() -> Box<[TypeId]> { - set_by_index_token().input_types() } } }; diff --git a/codegen/ui_tests/rhai_mod_unknown_type.stderr b/codegen/ui_tests/rhai_mod_unknown_type.stderr index 1b400234..5f61d9d3 100644 --- a/codegen/ui_tests/rhai_mod_unknown_type.stderr +++ b/codegen/ui_tests/rhai_mod_unknown_type.stderr @@ -15,7 +15,7 @@ help: consider importing one of these items | 11 | use core::fmt::Pointer; | -11 | use crate::new_vec::fmt::Pointer; +11 | use crate::mem::fmt::Pointer; | 11 | use std::fmt::Pointer; | diff --git a/examples/strings.rs b/examples/strings.rs index f10fac94..ba5749ec 100644 --- a/examples/strings.rs +++ b/examples/strings.rs @@ -21,7 +21,7 @@ fn count_string_bytes(s: &str) -> INT { /// This version uses `ImmutableString` and `&str`. fn find_substring(s: ImmutableString, sub: &str) -> INT { - s.as_str().find(sub).map(|x| x as INT).unwrap_or(-1) + s.find(sub).map(|x| x as INT).unwrap_or(-1) } fn main() -> Result<(), Box> { diff --git a/src/ast.rs b/src/ast.rs index f420ae7a..51da78e6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,7 +6,7 @@ use crate::module::NamespaceRef; use crate::stdlib::{ borrow::Cow, boxed::Box, - collections::BTreeMap, + collections::{BTreeMap, BTreeSet}, fmt, hash::Hash, num::NonZeroUsize, @@ -26,9 +26,6 @@ use crate::{stdlib::str::FromStr, FLOAT}; #[cfg(not(feature = "no_index"))] use crate::Array; -#[cfg(not(feature = "no_object"))] -use crate::Map; - /// A type representing the access mode of a function. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum FnAccess { @@ -61,7 +58,7 @@ pub struct ScriptFnDef { pub params: StaticVec, /// Access to external variables. #[cfg(not(feature = "no_closure"))] - pub externals: StaticVec, + pub externals: BTreeSet, /// Function doc-comments (if any). pub comments: StaticVec, } @@ -87,6 +84,7 @@ impl fmt::Display for ScriptFnDef { } /// A type containing the metadata of a script-defined function. +/// Not available under `no_function`. /// /// Created by [`AST::iter_functions`]. #[cfg(not(feature = "no_function"))] @@ -263,6 +261,7 @@ impl AST { } /// _(INTERNALS)_ Get the internal shared [`Module`] containing all script-defined functions. /// Exported under the `internals` feature only. + /// Not available under `no_function`. #[cfg(feature = "internals")] #[deprecated = "this method is volatile and may change"] #[cfg(not(feature = "no_module"))] @@ -279,6 +278,7 @@ impl AST { } /// _(INTERNALS)_ Get the internal [`Module`] containing all script-defined functions. /// Exported under the `internals` feature only. + /// Not available under `no_function`. #[cfg(feature = "internals")] #[deprecated = "this method is volatile and may change"] #[inline(always)] @@ -314,10 +314,9 @@ impl AST { } /// Clone the [`AST`]'s functions into a new [`AST`]. /// No statements are cloned. + /// Not available under `no_function`. /// /// This operation is cheap because functions are shared. - /// - /// Not available under `no_function`. #[cfg(not(feature = "no_function"))] #[inline(always)] pub fn clone_functions_only(&self) -> Self { @@ -325,10 +324,9 @@ impl AST { } /// Clone the [`AST`]'s functions into a new [`AST`] based on a filter predicate. /// No statements are cloned. + /// Not available under `no_function`. /// /// This operation is cheap because functions are shared. - /// - /// Not available under `no_function`. #[cfg(not(feature = "no_function"))] #[inline(always)] pub fn clone_functions_only_filtered( @@ -357,8 +355,8 @@ impl AST { resolver: self.resolver.clone(), } } - /// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version - /// is returned. + /// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, + /// version is returned. /// /// Statements in the second [`AST`] are simply appended to the end of the first _without any processing_. /// Thus, the return value of the first [`AST`] (if using expression-statement syntax) is buried. @@ -1288,7 +1286,7 @@ pub struct BinaryExpr { pub struct OpAssignment { pub hash_op_assign: u64, pub hash_op: u64, - pub op: Cow<'static, str>, + pub op: &'static str, } /// _(INTERNALS)_ An set of function call hashes. @@ -1516,7 +1514,7 @@ impl FloatWrapper { #[derive(Debug, Clone, Hash)] pub enum Expr { /// Dynamic constant. - /// Used to hold either an [`Array`] or [`Map`] literal for quick cloning. + /// Used to hold either an [`Array`] or [`Map`][crate::Map] literal for quick cloning. /// All other primitive data types should use the appropriate variants for better speed. DynamicConstant(Box, Position), /// Boolean constant. @@ -1535,7 +1533,10 @@ pub enum Expr { /// [ expr, ... ] Array(Box>, Position), /// #{ name:expr, ... } - Map(Box>, Position), + Map( + Box<(StaticVec<(Ident, Expr)>, BTreeMap)>, + Position, + ), /// () Unit(Position), /// Variable access - (optional index, optional (hash, modules), variable name) @@ -1594,11 +1595,10 @@ impl Expr { #[cfg(not(feature = "no_object"))] Self::Map(x, _) if self.is_constant() => { - let mut map = Map::new(); - map.extend( - x.iter() - .map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), - ); + let mut map = x.1.clone(); + x.0.iter().for_each(|(k, v)| { + *map.get_mut(&k.name).unwrap() = v.get_constant_value().unwrap() + }); Dynamic(Union::Map(Box::new(map), AccessMode::ReadOnly)) } @@ -1677,7 +1677,7 @@ impl Expr { match self { Self::Array(x, _) => x.iter().all(Self::is_pure), - Self::Map(x, _) => x.iter().map(|(_, v)| v).all(Self::is_pure), + Self::Map(x, _) => x.0.iter().map(|(_, v)| v).all(Self::is_pure), Self::Index(x, _) | Self::And(x, _) | Self::Or(x, _) => { x.lhs.is_pure() && x.rhs.is_pure() @@ -1717,7 +1717,7 @@ impl Expr { Self::Array(x, _) => x.iter().all(Self::is_constant), // An map literal is constant if all items are constant - Self::Map(x, _) => x.iter().map(|(_, expr)| expr).all(Self::is_constant), + Self::Map(x, _) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant), _ => false, } @@ -1804,7 +1804,7 @@ impl Expr { } } Self::Map(x, _) => { - for (_, e) in x.as_ref() { + for (_, e) in &x.0 { if !e.walk(path, on_node) { return false; } @@ -1856,7 +1856,7 @@ mod tests { assert_eq!(size_of::>(), 16); assert_eq!(size_of::(), 40); assert_eq!(size_of::>(), 40); - assert_eq!(size_of::(), 32); + assert_eq!(size_of::(), 80); assert_eq!(size_of::(), 288); assert_eq!(size_of::(), 56); assert_eq!(size_of::(), 16); diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 291842e2..5dc2fd75 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -45,6 +45,7 @@ fn print_help() { println!("help => print this help"); println!("quit, exit => quit"); println!("scope => print all variables in the scope"); + #[cfg(feature = "metadata")] println!("functions => print all functions defined"); println!("ast => print the last AST (optimized)"); println!("astu => print the last raw, un-optimized AST"); @@ -202,6 +203,7 @@ fn main() { println!("{:#?}\n", ast); continue; } + #[cfg(feature = "metadata")] "functions" => { // print a list of all registered functions engine diff --git a/src/dynamic.rs b/src/dynamic.rs index 014a0ed9..6c3f9dbf 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -1349,7 +1349,7 @@ impl Dynamic { } if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Str(value, _) => ::downcast_ref::(value.as_ref()), + Union::Str(value, _) => ::downcast_ref::(value.as_ref() as &String), _ => None, }; } diff --git a/src/engine.rs b/src/engine.rs index 4d1a9541..8652ef25 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -75,7 +75,7 @@ impl Imports { .iter() .enumerate() .rev() - .find_map(|(i, key)| if key.as_str() == name { Some(i) } else { None }) + .find_map(|(i, key)| if *key == name { Some(i) } else { None }) } /// Push an imported [modules][Module] onto the stack. #[inline(always)] @@ -342,13 +342,13 @@ impl<'a> Target<'a> { #[inline(always)] pub fn is(&self) -> bool { match self { - Target::Ref(r) => r.is::(), + Self::Ref(r) => r.is::(), #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_object"))] - Target::LockGuard((r, _)) => r.is::(), - Target::Value(r) => r.is::(), + Self::LockGuard((r, _)) => r.is::(), + Self::Value(r) => r.is::(), #[cfg(not(feature = "no_index"))] - Target::StringChar(_, _, _) => TypeId::of::() == TypeId::of::(), + Self::StringChar(_, _, _) => TypeId::of::() == TypeId::of::(), } } /// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary. @@ -996,12 +996,12 @@ impl Engine { }; // Check if the variable is `this` - if name.as_str() == KEYWORD_THIS { - if let Some(val) = this_ptr { - return Ok(((*val).into(), *pos)); + if *name == KEYWORD_THIS { + return if let Some(val) = this_ptr { + Ok(((*val).into(), *pos)) } else { - return EvalAltResult::ErrorUnboundThis(*pos).into(); - } + EvalAltResult::ErrorUnboundThis(*pos).into() + }; } // Check if it is directly indexed @@ -1056,7 +1056,7 @@ impl Engine { idx_values: &mut StaticVec, chain_type: ChainType, level: usize, - new_val: Option<((Dynamic, Position), (&Option, Position))>, + new_val: Option<((Dynamic, Position), (Option, Position))>, ) -> Result<(Dynamic, bool), Box> { assert!(chain_type != ChainType::NonChaining); @@ -1097,6 +1097,8 @@ impl Engine { // xxx[rhs] op= new_val _ if new_val.is_some() => { let idx_val = idx_val.as_index_value(); + + #[cfg(not(feature = "no_index"))] let mut idx_val2 = idx_val.clone(); // `call_setter` is introduced to bypass double mutable borrowing of target @@ -1357,7 +1359,7 @@ impl Engine { this_ptr: &mut Option<&mut Dynamic>, expr: &Expr, level: usize, - new_val: Option<((Dynamic, Position), (&Option, Position))>, + new_val: Option<((Dynamic, Position), (Option, Position))>, ) -> RhaiResult { let (crate::ast::BinaryExpr { lhs, rhs }, chain_type, op_pos) = match expr { Expr::Index(x, pos) => (x.as_ref(), ChainType::Index, *pos), @@ -1524,7 +1526,7 @@ impl Engine { state: &mut State, _lib: &[&Module], target: &'t mut Dynamic, - idx: Dynamic, + mut idx: Dynamic, idx_pos: Position, _create: bool, _is_ref: bool, @@ -1557,21 +1559,18 @@ impl Engine { #[cfg(not(feature = "no_object"))] Dynamic(Union::Map(map, _)) => { // val_map[idx] - Ok(if _create { - let index = idx.take_immutable_string().map_err(|err| { - self.make_type_mismatch_err::(err, idx_pos) - })?; + let index = &*idx.read_lock::().ok_or_else(|| { + self.make_type_mismatch_err::(idx.type_name(), idx_pos) + })?; - map.entry(index).or_insert_with(Default::default).into() - } else { - let index = idx.read_lock::().ok_or_else(|| { - self.make_type_mismatch_err::("", idx_pos) - })?; + if _create && !map.contains_key(index) { + map.insert(index.clone(), Default::default()); + } - map.get_mut(&*index) - .map(Target::from) - .unwrap_or_else(|| Target::from(())) - }) + Ok(map + .get_mut(index) + .map(Target::from) + .unwrap_or_else(|| Target::from(()))) } #[cfg(not(feature = "no_index"))] @@ -1596,7 +1595,6 @@ impl Engine { #[cfg(not(feature = "no_index"))] _ if _indexers => { let type_name = target.type_name(); - let mut idx = idx; let args = &mut [target, &mut idx]; let hash_get = FnCallHash::from_native(calc_fn_hash(empty(), FN_IDX_GET, 2)); self.exec_fn_call( @@ -1686,13 +1684,11 @@ impl Engine { #[cfg(not(feature = "no_object"))] Expr::Map(x, _) => { - let mut map = Map::new(); - for (Ident { name: key, .. }, expr) in x.as_ref() { - map.insert( - key.clone(), - self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? - .flatten(), - ); + let mut map = x.1.clone(); + for (Ident { name: key, .. }, expr) in &x.0 { + *map.get_mut(key).unwrap() = self + .eval_expr(scope, mods, state, lib, this_ptr, expr, level)? + .flatten(); } Ok(Dynamic(Union::Map(Box::new(map), AccessMode::ReadWrite))) } @@ -1865,7 +1861,7 @@ impl Engine { mods: &mut Imports, state: &mut State, lib: &[&Module], - op_info: &Option, + op_info: Option, op_pos: Position, mut target: Target, mut new_value: Dynamic, @@ -1891,20 +1887,19 @@ impl Engine { lhs_ptr_inner = target.as_mut(); } - let hash = *hash_op_assign; + let hash = hash_op_assign; let args = &mut [lhs_ptr_inner, &mut new_value]; match self.call_native_fn(mods, state, lib, op, hash, args, true, true, op_pos) { Ok(_) => (), - Err(err) if matches!(err.as_ref(), EvalAltResult::ErrorFunctionNotFound(f, _) if f.starts_with(op.as_ref())) => + Err(err) if matches!(err.as_ref(), EvalAltResult::ErrorFunctionNotFound(f, _) if f.starts_with(op)) => { // Expand to `var = var op rhs` let op = &op[..op.len() - 1]; // extract operator without = // Run function - let (value, _) = self.call_native_fn( - mods, state, lib, op, *hash_op, args, true, false, op_pos, - )?; + let (value, _) = self + .call_native_fn(mods, state, lib, op, hash_op, args, true, false, op_pos)?; *args[0] = value.flatten(); } @@ -1977,7 +1972,7 @@ impl Engine { mods, state, lib, - op_info, + op_info.clone(), *op_pos, lhs_ptr, rhs_val, @@ -1993,7 +1988,7 @@ impl Engine { let rhs_val = self .eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)? .flatten(); - let _new_val = Some(((rhs_val, rhs_expr.position()), (op_info, *op_pos))); + let _new_val = Some(((rhs_val, rhs_expr.position()), (op_info.clone(), *op_pos))); // Must be either `var[index] op= val` or `var.prop op= val` match lhs_expr { diff --git a/src/engine_api.rs b/src/engine_api.rs index 86c523d7..96abbbbf 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -9,12 +9,11 @@ use crate::stdlib::{ any::{type_name, TypeId}, boxed::Box, format, - string::{String, ToString}, - vec::Vec, + string::String, }; use crate::{ - scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Module, NativeCallContext, - ParseError, Position, RhaiResult, Shared, StaticVec, AST, + scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, + NativeCallContext, ParseError, Position, RhaiResult, Shared, AST, }; #[cfg(not(feature = "no_index"))] @@ -52,26 +51,36 @@ impl Engine { /// # } /// ``` #[inline] - pub fn register_fn(&mut self, name: &str, func: F) -> &mut Self + pub fn register_fn(&mut self, name: N, func: F) -> &mut Self where + N: AsRef + Into, F: RegisterNativeFunction, { let param_types = F::param_types(); - let mut param_type_names: StaticVec<_> = F::param_names() + + #[cfg(feature = "metadata")] + let mut param_type_names: crate::StaticVec<_> = F::param_names() .iter() .map(|ty| format!("_: {}", self.map_type_name(ty))) .collect(); + + #[cfg(feature = "metadata")] if F::return_type() != TypeId::of::<()>() { - param_type_names.push(self.map_type_name(F::return_type_name()).to_string()); + param_type_names.push(self.map_type_name(F::return_type_name()).into()); } - let param_type_names: StaticVec<_> = - param_type_names.iter().map(|ty| ty.as_str()).collect(); + + #[cfg(feature = "metadata")] + let param_type_names: Option> = + Some(param_type_names.iter().map(|ty| ty.as_str()).collect()); + + #[cfg(not(feature = "metadata"))] + let param_type_names: Option<[&str; 0]> = None; self.global_namespace.set_fn( name, FnNamespace::Global, FnAccess::Public, - Some(¶m_type_names), + param_type_names.as_ref().map(|v| v.as_ref()), ¶m_types, func.into_callable_function(), ); @@ -102,24 +111,34 @@ impl Engine { /// .expect_err("expecting division by zero error!"); /// ``` #[inline] - pub fn register_result_fn(&mut self, name: &str, func: F) -> &mut Self + pub fn register_result_fn(&mut self, name: N, func: F) -> &mut Self where + N: AsRef + Into, F: RegisterNativeFunction>>, { let param_types = F::param_types(); - let mut param_type_names: StaticVec<_> = F::param_names() + + #[cfg(feature = "metadata")] + let param_type_names: crate::StaticVec<_> = F::param_names() .iter() .map(|ty| format!("_: {}", self.map_type_name(ty))) + .chain(crate::stdlib::iter::once( + self.map_type_name(F::return_type_name()).into(), + )) .collect(); - param_type_names.push(self.map_type_name(F::return_type_name()).to_string()); - let param_type_names: StaticVec<&str> = - param_type_names.iter().map(|ty| ty.as_str()).collect(); + + #[cfg(feature = "metadata")] + let param_type_names: Option> = + Some(param_type_names.iter().map(|ty| ty.as_str()).collect()); + + #[cfg(not(feature = "metadata"))] + let param_type_names: Option<[&str; 0]> = None; self.global_namespace.set_fn( name, FnNamespace::Global, FnAccess::Public, - Some(¶m_type_names), + param_type_names.as_ref().map(|v| v.as_ref()), ¶m_types, func.into_callable_function(), ); @@ -142,14 +161,18 @@ impl Engine { /// To access the first mutable parameter, use `args.get_mut(0).unwrap()` #[deprecated = "this function is volatile and may change"] #[inline(always)] - pub fn register_raw_fn( + pub fn register_raw_fn( &mut self, - name: &str, + name: N, arg_types: &[TypeId], func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result> + SendSync + 'static, - ) -> &mut Self { + ) -> &mut Self + where + N: AsRef + Into, + T: Variant + Clone, + { self.global_namespace.set_raw_fn( name, FnNamespace::Global, @@ -878,25 +901,29 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_module"))] - pub fn register_static_module(&mut self, name: &str, module: Shared) -> &mut Self { + pub fn register_static_module( + &mut self, + name: impl AsRef + Into, + module: Shared, + ) -> &mut Self { fn register_static_module_raw( root: &mut crate::stdlib::collections::BTreeMap>, - name: &str, + name: impl AsRef + Into, module: Shared, ) { let separator = crate::token::Token::DoubleColon.syntax(); - if !name.contains(separator.as_ref()) { + if !name.as_ref().contains(separator.as_ref()) { if !module.is_indexed() { // Index the module (making a clone copy if necessary) if it is not indexed let mut module = crate::fn_native::shared_take_or_clone(module); module.build_index(); - root.insert(name.trim().into(), module.into()); + root.insert(name.into(), module.into()); } else { - root.insert(name.trim().into(), module); + root.insert(name.into(), module); } } else { - let mut iter = name.splitn(2, separator.as_ref()); + let mut iter = name.as_ref().splitn(2, separator.as_ref()); let sub_module = iter.next().unwrap().trim(); let remainder = iter.next().unwrap().trim(); @@ -915,7 +942,7 @@ impl Engine { } } - register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module); + register_static_module_raw(&mut self.global_sub_modules, name, module); self } @@ -927,7 +954,11 @@ impl Engine { #[cfg(not(feature = "no_module"))] #[inline(always)] #[deprecated = "use `register_static_module` instead"] - pub fn register_module(&mut self, name: &str, module: impl Into>) -> &mut Self { + pub fn register_module( + &mut self, + name: impl AsRef + Into, + module: impl Into>, + ) -> &mut Self { self.register_static_module(name, module.into()) } /// Compile a string into an [`AST`], which can be used later for evaluation. @@ -1013,7 +1044,6 @@ impl Engine { fn_native::shared_take_or_clone, module::resolvers::StaticModuleResolver, stdlib::collections::BTreeSet, - ImmutableString, }; fn collect_imports( @@ -1232,7 +1262,7 @@ impl Engine { Self::read_file(path).and_then(|contents| Ok(self.compile_with_scope(scope, &contents)?)) } /// Parse a JSON string into an [object map][`Map`]. - /// This is a light-weight alternative to using, say, [`serde_json`][https://crates.io/crates/serde_json] to deserialize the JSON. + /// This is a light-weight alternative to using, say, [`serde_json`] to deserialize the JSON. /// /// The JSON string must be an object hash. It cannot be a simple scalar value. /// @@ -1271,16 +1301,21 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_object"))] - pub fn parse_json(&self, json: &str, has_null: bool) -> Result> { + pub fn parse_json( + &self, + json: impl AsRef, + has_null: bool, + ) -> Result> { use crate::token::Token; + let json = json.as_ref(); let mut scope = Default::default(); // Trims the JSON string and add a '#' in front let json_text = json.trim_start(); - let scripts = if json_text.starts_with(Token::MapStart.syntax().as_ref()) { + let scripts = if json_text.starts_with(Token::MapStart.keyword_syntax()) { [json_text, ""] - } else if json_text.starts_with(Token::LeftBrace.syntax().as_ref()) { + } else if json_text.starts_with(Token::LeftBrace.keyword_syntax()) { ["#", json_text] } else { return Err(crate::ParseErrorType::MissingToken( @@ -1765,7 +1800,7 @@ impl Engine { &self, scope: &mut Scope, ast: &AST, - name: &str, + name: impl AsRef, args: impl crate::fn_args::FuncArgs, ) -> Result> { let mut arg_values: crate::StaticVec<_> = Default::default(); @@ -1844,7 +1879,7 @@ impl Engine { scope: &mut Scope, ast: &AST, eval_ast: bool, - name: &str, + name: impl AsRef, mut this_ptr: Option<&mut Dynamic>, mut arg_values: impl AsMut<[Dynamic]>, ) -> RhaiResult { @@ -1867,7 +1902,7 @@ impl Engine { scope: &mut Scope, ast: &AST, eval_ast: bool, - name: &str, + name: impl AsRef, this_ptr: &mut Option<&mut Dynamic>, args: &mut FnCallArgs, ) -> RhaiResult { @@ -1881,12 +1916,14 @@ impl Engine { let fn_def = ast .lib() - .get_script_fn(name, args.len()) - .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?; + .get_script_fn(name.as_ref(), args.len()) + .ok_or_else(|| { + EvalAltResult::ErrorFunctionNotFound(name.as_ref().into(), Position::NONE) + })?; // Check for data race. #[cfg(not(feature = "no_closure"))] - crate::fn_call::ensure_no_data_race(name, args, false)?; + crate::fn_call::ensure_no_data_race(name.as_ref(), args, false)?; self.call_script_fn( scope, @@ -1936,13 +1973,15 @@ impl Engine { crate::optimize::optimize_into_ast(self, scope, stmt.into_vec(), lib, optimization_level) } /// Generate a list of all registered functions. + /// Available under the `metadata` feature only. /// /// Functions from the following sources are included, in order: /// 1) Functions registered into the global namespace /// 2) Functions in registered sub-modules /// 3) Functions in packages (optional) - pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec { - let mut signatures: Vec<_> = Default::default(); + #[cfg(feature = "metadata")] + pub fn gen_fn_signatures(&self, include_packages: bool) -> crate::stdlib::vec::Vec { + let mut signatures: crate::stdlib::vec::Vec<_> = Default::default(); signatures.extend(self.global_namespace.gen_fn_signatures()); diff --git a/src/engine_settings.rs b/src/engine_settings.rs index 1bf32f1a..b666714e 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -236,7 +236,7 @@ impl Engine { /// # } /// ``` #[inline(always)] - pub fn disable_symbol(&mut self, symbol: &str) -> &mut Self { + pub fn disable_symbol(&mut self, symbol: impl Into) -> &mut Self { self.disabled_symbols.insert(symbol.into()); self } @@ -270,7 +270,7 @@ impl Engine { /// ``` pub fn register_custom_operator( &mut self, - keyword: &str, + keyword: impl AsRef + Into, precedence: u8, ) -> Result<&mut Self, String> { let precedence = Precedence::new(precedence); @@ -279,25 +279,25 @@ impl Engine { return Err("precedence cannot be zero".into()); } - match Token::lookup_from_syntax(keyword) { + match Token::lookup_from_syntax(keyword.as_ref()) { // Standard identifiers, reserved keywords and custom keywords are OK None | Some(Token::Reserved(_)) | Some(Token::Custom(_)) => (), // Active standard keywords cannot be made custom // Disabled keywords are OK Some(token) if token.is_keyword() => { if !self.disabled_symbols.contains(token.syntax().as_ref()) { - return Err(format!("'{}' is a reserved keyword", keyword).into()); + return Err(format!("'{}' is a reserved keyword", keyword.as_ref()).into()); } } // Active standard symbols cannot be made custom Some(token) if token.is_symbol() => { if !self.disabled_symbols.contains(token.syntax().as_ref()) { - return Err(format!("'{}' is a reserved operator", keyword).into()); + return Err(format!("'{}' is a reserved operator", keyword.as_ref()).into()); } } // Active standard symbols cannot be made custom Some(token) if !self.disabled_symbols.contains(token.syntax().as_ref()) => { - return Err(format!("'{}' is a reserved symbol", keyword).into()) + return Err(format!("'{}' is a reserved symbol", keyword.as_ref()).into()) } // Disabled symbols are OK Some(_) => (), diff --git a/src/fn_args.rs b/src/fn_args.rs index 90a5d3f3..13dabf2f 100644 --- a/src/fn_args.rs +++ b/src/fn_args.rs @@ -26,7 +26,7 @@ pub trait FuncArgs { /// } /// /// impl FuncArgs for Options { - /// fn parse>(self, container: &mut C) { + /// fn parse>(self, container: &mut CONTAINER) { /// container.extend(std::iter::once(self.foo.into())); /// container.extend(std::iter::once(self.bar.into())); /// container.extend(std::iter::once(self.baz.into())); @@ -51,11 +51,12 @@ pub trait FuncArgs { /// # Ok(()) /// # } /// ``` - fn parse>(self, container: &mut T); + fn parse>(self, container: &mut CONTAINER); } impl FuncArgs for Vec { - fn parse>(self, container: &mut C) { + #[inline(always)] + fn parse>(self, container: &mut CONTAINER) { container.extend(self.into_iter().map(Variant::into_dynamic)); } } diff --git a/src/fn_call.rs b/src/fn_call.rs index 17356679..18cc509c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -475,9 +475,9 @@ impl Engine { fn_def .lib .as_ref() - .and_then(|m| m.id()) - .unwrap_or_else(|| state.source.as_ref().map_or_else(|| "", |s| s.as_str())) - .to_string(), + .and_then(|m| m.id().map(|id| id.to_string())) + .or_else(|| state.source.as_ref().map(|s| s.to_string())) + .unwrap_or_default(), err, pos, ) @@ -651,14 +651,14 @@ impl Engine { crate::engine::KEYWORD_IS_DEF_FN if args.len() == 2 && args[0].is::() && args[1].is::() => { - let fn_name = args[0].read_lock::().unwrap(); + let fn_name = &*args[0].read_lock::().unwrap(); let num_params = args[1].as_int().unwrap(); return Ok(( if num_params < 0 { Dynamic::FALSE } else { - let hash_script = calc_fn_hash(empty(), &fn_name, num_params as usize); + let hash_script = calc_fn_hash(empty(), fn_name, num_params as usize); self.has_script_fn(Some(mods), state, lib, hash_script) .into() }, @@ -737,7 +737,7 @@ impl Engine { if !func.externals.is_empty() { captured .into_iter() - .filter(|(name, _, _)| func.externals.iter().any(|ex| ex == name)) + .filter(|(name, _, _)| func.externals.contains(name.as_ref())) .for_each(|(name, value, _)| { // Consume the scope values. scope.push_dynamic(name, value); @@ -1132,13 +1132,10 @@ impl Engine { // Append the new curried arguments to the existing list. - args_expr.iter().skip(1).try_for_each( - |expr| -> Result<(), Box> { - fn_curry - .push(self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?); - Ok(()) - }, - )?; + args_expr.iter().skip(1).try_for_each(|expr| { + self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(|value| fn_curry.push(value)) + })?; return Ok(FnPtr::new_unchecked(name, fn_curry).into()); } @@ -1222,8 +1219,8 @@ impl Engine { state .source .as_ref() - .map_or_else(|| "", |s| s.as_str()) - .to_string(), + .map(|s| s.to_string()) + .unwrap_or_default(), err, pos, )) diff --git a/src/fn_native.rs b/src/fn_native.rs index 12cb94b6..e893550b 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -7,15 +7,14 @@ use crate::stdlib::{ boxed::Box, convert::{TryFrom, TryInto}, fmt, - iter::empty, + iter::{empty, once}, mem, string::String, - vec::Vec, }; use crate::token::is_valid_identifier; use crate::{ calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ImmutableString, Module, Position, - RhaiResult, + RhaiResult, StaticVec, }; /// Trait that maps to `Send + Sync` only under the `sync` feature. @@ -185,10 +184,12 @@ impl<'a> NativeCallContext<'a> { #[inline(always)] pub fn call_fn_dynamic_raw( &self, - fn_name: &str, + fn_name: impl AsRef, is_method: bool, args: &mut [&mut Dynamic], ) -> RhaiResult { + let fn_name = fn_name.as_ref(); + let hash = if is_method { FnCallHash::from_script_and_native( calc_fn_hash(empty(), fn_name, args.len() - 1), @@ -251,7 +252,7 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic]; /// A general function pointer, which may carry additional (i.e. curried) argument values /// to be passed onto a function during a call. #[derive(Debug, Clone)] -pub struct FnPtr(ImmutableString, Vec); +pub struct FnPtr(ImmutableString, StaticVec); impl FnPtr { /// Create a new function pointer. @@ -261,7 +262,10 @@ impl FnPtr { } /// Create a new function pointer without checking its parameters. #[inline(always)] - pub(crate) fn new_unchecked(name: impl Into, curry: Vec) -> Self { + pub(crate) fn new_unchecked( + name: impl Into, + curry: StaticVec, + ) -> Self { Self(name.into(), curry) } /// Get the name of the function. @@ -276,7 +280,7 @@ impl FnPtr { } /// Get the underlying data of the function pointer. #[inline(always)] - pub(crate) fn take_data(self) -> (ImmutableString, Vec) { + pub(crate) fn take_data(self) -> (ImmutableString, StaticVec) { (self.0, self.1) } /// Get the curried arguments. @@ -324,22 +328,28 @@ impl FnPtr { this_ptr: Option<&mut Dynamic>, mut arg_values: impl AsMut<[Dynamic]>, ) -> RhaiResult { - let arg_values = arg_values.as_mut(); + let mut args_data; - let mut args_data = self - .curry() - .iter() - .cloned() - .chain(arg_values.iter_mut().map(mem::take)) - .collect::>(); + let arg_values = if self.curry().is_empty() { + arg_values.as_mut() + } else { + args_data = self + .curry() + .iter() + .cloned() + .chain(arg_values.as_mut().iter_mut().map(mem::take)) + .collect::>(); - let mut args = args_data.iter_mut().collect::>(); + args_data.as_mut() + }; let is_method = this_ptr.is_some(); - if let Some(obj) = this_ptr { - args.insert(0, obj); - } + let mut args: StaticVec<_> = if let Some(obj) = this_ptr { + once(obj).chain(arg_values.iter_mut()).collect() + } else { + arg_values.iter_mut().collect() + }; ctx.call_fn_dynamic_raw(self.fn_name(), is_method, args.as_mut()) } diff --git a/src/fn_register.rs b/src/fn_register.rs index 7d04bdb2..134e55ad 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -5,13 +5,7 @@ use crate::dynamic::{DynamicWriteLock, Variant}; use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync}; use crate::r#unsafe::unsafe_try_cast; -use crate::stdlib::{ - any::{type_name, TypeId}, - boxed::Box, - mem, - string::String, - vec, -}; +use crate::stdlib::{any::TypeId, boxed::Box, mem, string::String, vec}; use crate::{Dynamic, EvalAltResult, NativeCallContext}; // These types are used to build a unique _marker_ tuple type for each combination @@ -61,16 +55,22 @@ pub fn by_value(data: &mut Dynamic) -> T { /// Trait to register custom Rust functions. pub trait RegisterNativeFunction { + /// Convert this function into a [`CallableFunction`]. + fn into_callable_function(self) -> CallableFunction; /// Get the type ID's of this function's parameters. fn param_types() -> Box<[TypeId]>; /// Get the type names of this function's parameters. + /// Available under the `metadata` feature only. + #[cfg(feature = "metadata")] fn param_names() -> Box<[&'static str]>; /// Get the type ID of this function's return value. + /// Available under the `metadata` feature only. + #[cfg(feature = "metadata")] fn return_type() -> TypeId; /// Get the type name of this function's return value. + /// Available under the `metadata` feature only. + #[cfg(feature = "metadata")] fn return_type_name() -> &'static str; - /// Convert this function into a [`CallableFunction`]. - fn into_callable_function(self) -> CallableFunction; } macro_rules! def_register { @@ -91,9 +91,9 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<($($mark,)*), ()> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(type_name::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } - #[inline(always)] fn return_type_name() -> &'static str { type_name::() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(crate::stdlib::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { crate::stdlib::any::type_name::() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! @@ -115,9 +115,9 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), ()> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(type_name::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } - #[inline(always)] fn return_type_name() -> &'static str { type_name::() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(crate::stdlib::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { crate::stdlib::any::type_name::() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! @@ -139,9 +139,9 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<($($mark,)*), Result>> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(type_name::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn return_type() -> TypeId { TypeId::of::>>() } - #[inline(always)] fn return_type_name() -> &'static str { type_name::>>() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(crate::stdlib::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>>() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { crate::stdlib::any::type_name::>>() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! @@ -160,9 +160,9 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), Result>> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(type_name::<$par>()),*].into_boxed_slice() } - #[inline(always)] fn return_type() -> TypeId { TypeId::of::>>() } - #[inline(always)] fn return_type_name() -> &'static str { type_name::>>() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(crate::stdlib::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>>() } + #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { crate::stdlib::any::type_name::>>() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! diff --git a/src/module/mod.rs b/src/module/mod.rs index 13b8c405..e0d9a60b 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -12,10 +12,11 @@ use crate::stdlib::{ iter::empty, num::NonZeroUsize, ops::{Add, AddAssign, Deref, DerefMut}, - string::{String, ToString}, + string::String, vec::Vec, }; use crate::token::Token; +use crate::utils::StringInterner; use crate::{ calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString, NativeCallContext, Position, Shared, StaticVec, @@ -54,27 +55,27 @@ pub struct FuncInfo { /// Function access mode. pub access: FnAccess, /// Function name. - pub name: String, + pub name: ImmutableString, /// Number of parameters. pub params: usize, /// Parameter types (if applicable). pub param_types: StaticVec, /// Parameter names (if available). + #[cfg(feature = "metadata")] pub param_names: StaticVec, } impl FuncInfo { /// Generate a signature of the function. + /// Available under the `metadata` feature only. + #[cfg(feature = "metadata")] pub fn gen_signature(&self) -> String { let mut sig = format!("{}(", self.name); if !self.param_names.is_empty() { - let mut params: Vec<_> = self - .param_names - .iter() - .map(ImmutableString::to_string) - .collect(); - let return_type = params.pop().unwrap_or_else(|| "()".to_string()); + let mut params: crate::stdlib::vec::Vec = + self.param_names.iter().map(|s| s.as_str().into()).collect(); + let return_type = params.pop().unwrap_or_else(|| "()".into()); sig.push_str(¶ms.join(", ")); if return_type != "()" { sig.push_str(") -> "); @@ -114,7 +115,7 @@ impl FuncInfo { #[inline(always)] fn calc_native_fn_hash<'a>( modules: impl Iterator, - fn_name: &str, + fn_name: impl AsRef, params: &[TypeId], ) -> u64 { let hash_script = calc_fn_hash(modules, fn_name, params.len()); @@ -147,6 +148,8 @@ pub struct Module { indexed: bool, /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? contains_indexed_global_functions: bool, + /// Interned strings + interned_strings: StringInterner, } impl Default for Module { @@ -163,6 +166,7 @@ impl Default for Module { all_type_iterators: Default::default(), indexed: false, contains_indexed_global_functions: false, + interned_strings: Default::default(), } } } @@ -172,11 +176,10 @@ impl fmt::Debug for Module { write!( f, "Module({}\n{}{}{})", - if let Some(ref id) = self.id { - format!("id: {:?},", id) - } else { - "".to_string() - }, + self.id + .as_ref() + .map(|id| format!("id: {:?},", id)) + .unwrap_or_default(), if !self.modules.is_empty() { format!( " modules: {}\n", @@ -187,7 +190,7 @@ impl fmt::Debug for Module { .join(", ") ) } else { - "".to_string() + Default::default() }, if !self.variables.is_empty() { format!( @@ -199,19 +202,19 @@ impl fmt::Debug for Module { .join(", ") ) } else { - "".to_string() + Default::default() }, if !self.functions.is_empty() { format!( " functions: {}\n", self.functions .values() - .map(|f| f.func.to_string()) + .map(|f| crate::stdlib::string::ToString::to_string(&f.func)) .collect::>() .join(", ") ) } else { - "".to_string() + Default::default() } ) } @@ -360,6 +363,8 @@ impl Module { } /// Generate signatures for all the non-private functions in the [`Module`]. + /// Available under the `metadata` feature only. + #[cfg(feature = "metadata")] #[inline(always)] pub fn gen_fn_signatures(&self) -> impl Iterator + '_ { self.functions @@ -466,16 +471,17 @@ impl Module { // None + function name + number of arguments. let num_params = fn_def.params.len(); let hash_script = crate::calc_fn_hash(empty(), &fn_def.name, num_params); - let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect(); + let mut param_names = fn_def.params.clone(); param_names.push("Dynamic".into()); self.functions.insert( hash_script, Box::new(FuncInfo { - name: fn_def.name.to_string(), + name: fn_def.name.clone(), namespace: FnNamespace::Internal, access: fn_def.access, params: num_params, param_types: Default::default(), + #[cfg(feature = "metadata")] param_names, func: fn_def.into(), }), @@ -599,6 +605,7 @@ impl Module { } /// Update the metadata (parameter names/types and return type) of a registered function. + /// Available under the `metadata` feature only. /// /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call. /// @@ -610,10 +617,16 @@ impl Module { /// /// 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. + #[cfg(feature = "metadata")] #[inline(always)] pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self { + let param_names = arg_names + .iter() + .map(|&name| self.interned_strings.get(name)) + .collect(); + if let Some(f) = self.functions.get_mut(&hash_fn) { - f.param_names = arg_names.iter().map(|&n| n.into()).collect(); + f.param_names = param_names; } self } @@ -625,9 +638,9 @@ impl Module { pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { if let Some(f) = self.functions.get_mut(&hash_fn) { f.namespace = namespace; + self.indexed = false; + self.contains_indexed_global_functions = false; } - self.indexed = false; - self.contains_indexed_global_functions = false; self } @@ -641,14 +654,13 @@ impl Module { #[inline] pub fn set_fn( &mut self, - name: impl Into, + name: impl AsRef + Into, namespace: FnNamespace, access: FnAccess, - arg_names: Option<&[&str]>, + _arg_names: Option<&[&str]>, arg_types: &[TypeId], func: CallableFunction, ) -> u64 { - let name = name.into(); let is_method = func.is_method(); let param_types = arg_types @@ -675,6 +687,15 @@ impl Module { let hash_fn = calc_native_fn_hash(empty(), &name, ¶m_types); + let name = self.interned_strings.get(name); + + #[cfg(feature = "metadata")] + let param_names = _arg_names + .iter() + .flat_map(|p| p.iter()) + .map(|&arg| self.interned_strings.get(arg)) + .collect(); + self.functions.insert( hash_fn, Box::new(FuncInfo { @@ -683,11 +704,8 @@ impl Module { access, params: param_types.len(), param_types, - param_names: if let Some(p) = arg_names { - p.iter().map(|&v| v.into()).collect() - } else { - Default::default() - }, + #[cfg(feature = "metadata")] + param_names, func: func.into(), }), ); @@ -765,16 +783,21 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline(always)] - pub fn set_raw_fn( + pub fn set_raw_fn( &mut self, - name: impl Into, + name: N, namespace: FnNamespace, access: FnAccess, arg_types: &[TypeId], - func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result> + func: F, + ) -> u64 + where + N: AsRef + Into, + T: Variant + Clone, + F: Fn(NativeCallContext, &mut FnCallArgs) -> Result> + SendSync + 'static, - ) -> u64 { + { let f = move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from); @@ -812,8 +835,9 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline(always)] - pub fn set_native_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_native_fn(&mut self, name: N, func: F) -> u64 where + N: AsRef + Into, T: Variant + Clone, F: RegisterNativeFunction>>, { @@ -847,7 +871,7 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_getter_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_getter_fn(&mut self, name: &str, func: F) -> u64 where A: Variant + Clone, T: Variant + Clone, @@ -855,7 +879,7 @@ impl Module { F: Fn(&mut A) -> Result> + SendSync + 'static, { self.set_fn( - crate::engine::make_getter(&name.into()), + &crate::engine::make_getter(name), FnNamespace::Global, FnAccess::Public, None, @@ -888,7 +912,7 @@ impl Module { /// ``` #[cfg(not(feature = "no_object"))] #[inline(always)] - pub fn set_setter_fn(&mut self, name: impl Into, func: F) -> u64 + pub fn set_setter_fn(&mut self, name: &str, func: F) -> u64 where A: Variant + Clone, B: Variant + Clone, @@ -896,7 +920,7 @@ impl Module { F: Fn(&mut A, B) -> Result<(), Box> + SendSync + 'static, { self.set_fn( - crate::engine::make_setter(&name.into()), + &crate::engine::make_setter(name), FnNamespace::Global, FnAccess::Public, None, @@ -1061,11 +1085,16 @@ impl Module { /// ``` #[cfg(not(feature = "no_index"))] #[inline(always)] - pub fn set_indexer_get_set_fn( + pub fn set_indexer_get_set_fn( &mut self, get_fn: impl Fn(&mut A, B) -> Result> + SendSync + 'static, set_fn: impl Fn(&mut A, B, T) -> Result<(), Box> + SendSync + 'static, - ) -> (u64, u64) { + ) -> (u64, u64) + where + A: Variant + Clone, + B: Variant + Clone, + T: Variant + Clone, + { ( self.set_indexer_get_fn(get_fn), self.set_indexer_set_fn(set_fn), diff --git a/src/optimize.rs b/src/optimize.rs index 37ac11ae..383ca44f 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -615,12 +615,12 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { #[cfg(not(feature = "no_object"))] Expr::Dot(x, _) => match (&mut x.lhs, &mut x.rhs) { // map.string - (Expr::Map(m, pos), Expr::Property(p)) if m.iter().all(|(_, x)| x.is_pure()) => { + (Expr::Map(m, pos), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => { let prop = &p.2.name; // Map literal where everything is pure - promote the indexed item. // All other items can be thrown away. state.set_dirty(); - *expr = mem::take(m).into_iter().find(|(x, _)| &x.name == prop) + *expr = mem::take(&mut m.0).into_iter().find(|(x, _)| &x.name == prop) .map(|(_, mut expr)| { expr.set_position(*pos); expr }) .unwrap_or_else(|| Expr::Unit(*pos)); } @@ -645,11 +645,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { *expr = result; } // map[string] - (Expr::Map(m, pos), Expr::StringConstant(s, _)) if m.iter().all(|(_, x)| x.is_pure()) => { + (Expr::Map(m, pos), Expr::StringConstant(s, _)) if m.0.iter().all(|(_, x)| x.is_pure()) => { // Map literal where everything is pure - promote the indexed item. // All other items can be thrown away. state.set_dirty(); - *expr = mem::take(m).into_iter().find(|(x, _)| x.name == *s) + *expr = mem::take(&mut m.0).into_iter().find(|(x, _)| x.name == *s) .map(|(_, mut expr)| { expr.set_position(*pos); expr }) .unwrap_or_else(|| Expr::Unit(*pos)); } @@ -681,7 +681,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { } // #{ key:value, .. } #[cfg(not(feature = "no_object"))] - Expr::Map(x, _) => x.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)), + Expr::Map(x, _) => x.0.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)), // lhs && rhs Expr::And(x, _) => match (&mut x.lhs, &mut x.rhs) { // true && rhs -> rhs diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 5eae23c6..9d482fae 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -142,8 +142,10 @@ macro_rules! reg_range { ($lib:ident | $x:expr => $( $y:ty ),*) => { $( $lib.set_iterator::>(); - let hash = $lib.set_native_fn($x, get_range::<$y>); - $lib.update_fn_metadata(hash, &[ + let _hash = $lib.set_native_fn($x, get_range::<$y>); + + #[cfg(feature = "metadata")] + $lib.update_fn_metadata(_hash, &[ concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("Iterator") @@ -153,8 +155,10 @@ macro_rules! reg_range { ($lib:ident | step $x:expr => $( $y:ty ),*) => { $( $lib.set_iterator::>(); - let hash = $lib.set_native_fn($x, get_step_range::<$y>); - $lib.update_fn_metadata(hash, &[ + let _hash = $lib.set_native_fn($x, get_step_range::<$y>); + + #[cfg(feature = "metadata")] + $lib.update_fn_metadata(_hash, &[ concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y)), @@ -251,10 +255,12 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { lib.set_iterator::(); - let hash = lib.set_native_fn("range", |from, to| StepDecimalRange::new(from, to, Decimal::one())); - lib.update_fn_metadata(hash, &["from: Decimal", "to: Decimal", "Iterator"]); + let _hash = lib.set_native_fn("range", |from, to| StepDecimalRange::new(from, to, Decimal::one())); + #[cfg(feature = "metadata")] + lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "Iterator"]); - let hash = lib.set_native_fn("range", |from, to, step| StepDecimalRange::new(from, to, step)); - lib.update_fn_metadata(hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator"]); + let _hash = lib.set_native_fn("range", |from, to, step| StepDecimalRange::new(from, to, step)); + #[cfg(feature = "metadata")] + lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator"]); } }); diff --git a/src/parser.rs b/src/parser.rs index de7a507e..fa5aa424 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -10,7 +10,6 @@ use crate::module::NamespaceRef; use crate::optimize::optimize_into_ast; use crate::optimize::OptimizationLevel; use crate::stdlib::{ - borrow::Cow, boxed::Box, collections::BTreeMap, format, @@ -23,7 +22,7 @@ use crate::stdlib::{ }; use crate::syntax::{CustomSyntax, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream}; -use crate::utils::get_hasher; +use crate::utils::{get_hasher, StringInterner}; use crate::{ calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position, Scope, Shared, StaticVec, AST, @@ -45,7 +44,7 @@ struct ParseState<'e> { /// Reference to the scripting [`Engine`]. engine: &'e Engine, /// Interned strings. - interned_strings: BTreeMap, + interned_strings: StringInterner, /// Encapsulates a local stack with variable names to simulate an actual runtime scope. stack: Vec<(ImmutableString, AccessMode)>, /// Size of the local variables stack upon entry of the current block scope. @@ -161,24 +160,17 @@ impl<'e> ParseState<'e> { .iter() .rev() .enumerate() - .find(|(_, n)| **n == name) + .find(|&(_, n)| *n == name) .and_then(|(i, _)| NonZeroUsize::new(i + 1)) } /// Get an interned string, creating one if it is not yet interned. + #[inline(always)] pub fn get_interned_string( &mut self, text: impl AsRef + Into, ) -> ImmutableString { - #[allow(clippy::map_entry)] - if !self.interned_strings.contains_key(text.as_ref()) { - let value = text.into(); - self.interned_strings - .insert(value.clone().into(), value.clone()); - value - } else { - self.interned_strings.get(text.as_ref()).unwrap().clone() - } + self.interned_strings.get(text) } } @@ -690,6 +682,7 @@ fn parse_map_literal( settings.pos = eat_token(input, Token::MapStart); let mut map: StaticVec<(Ident, Expr)> = Default::default(); + let mut template: BTreeMap = Default::default(); loop { const MISSING_RBRACE: &str = "to end this object map literal"; @@ -760,6 +753,7 @@ fn parse_map_literal( let expr = parse_expr(input, state, lib, settings.level_up())?; let name = state.get_interned_string(name); + template.insert(name.clone(), Default::default()); map.push((Ident { name, pos }, expr)); match input.peek().unwrap() { @@ -784,7 +778,7 @@ fn parse_map_literal( } } - Ok(Expr::Map(Box::new(map), settings.pos)) + Ok(Expr::Map(Box::new((map, template)), settings.pos)) } /// Parse a switch expression. @@ -1353,7 +1347,7 @@ fn parse_unary( /// Make an assignment statement. fn make_assignment_stmt<'a>( - op: Cow<'static, str>, + op: &'static str, state: &mut ParseState, lhs: Expr, rhs: Expr, @@ -1477,7 +1471,7 @@ fn parse_op_assignment_stmt( | Token::PowerOfAssign | Token::AndAssign | Token::OrAssign - | Token::XOrAssign => token.syntax(), + | Token::XOrAssign => token.keyword_syntax(), _ => return Ok(Stmt::Expr(lhs)), }; diff --git a/src/plugin.rs b/src/plugin.rs index 4a890af6..9ea4bb10 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,7 +1,7 @@ //! Module defining macros for developing _plugins_. pub use crate::fn_native::{CallableFunction, FnCallArgs}; -pub use crate::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString, vec as new_vec}; +pub use crate::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString}; pub use crate::{ Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, NativeCallContext, Position, @@ -26,13 +26,4 @@ pub trait PluginFunction { /// Is this plugin function variadic? fn is_variadic(&self) -> bool; - - /// Convert a plugin function into a boxed trait object. - fn clone_boxed(&self) -> Box; - - /// Return a boxed slice of the names of the function's parameters and return type. - fn param_names(&self) -> Box<[&'static str]>; - - /// Return a boxed slice of type ID's of the function's parameters. - fn input_types(&self) -> Box<[TypeId]>; } diff --git a/src/scope.rs b/src/scope.rs index 4ae73cbd..ac19bf2c 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -71,6 +71,7 @@ impl<'a> IntoIterator for Scope<'a> { type Item = (Cow<'a, str>, Dynamic); type IntoIter = Box + 'a>; + #[inline(always)] fn into_iter(self) -> Self::IntoIter { Box::new( self.values diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 3f8c9bed..dbb92ce3 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -211,7 +211,8 @@ impl From<&crate::Module> for ModuleMetadata { #[cfg(feature = "metadata")] impl Engine { /// _(METADATA)_ Generate a list of all functions (including those defined in an - /// [`AST`][crate::AST]) in JSON format. Available only under the `metadata` feature. + /// [`AST`][crate::AST]) in JSON format. + /// Available under the `metadata` feature only. /// /// Functions from the following sources are included: /// 1) Functions defined in an [`AST`][crate::AST] diff --git a/src/serde/mod.rs b/src/serde/mod.rs index a3819556..adb605de 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -8,6 +8,7 @@ mod serialize; mod str; #[cfg(feature = "metadata")] +#[cfg(feature = "serde")] mod metadata; pub use de::from_dynamic; diff --git a/src/token.rs b/src/token.rs index 4c697381..dba17351 100644 --- a/src/token.rs +++ b/src/token.rs @@ -381,6 +381,99 @@ pub enum Token { } impl Token { + /// Get the syntax of the token if it is a keyword. + /// + /// # Panics + /// + /// Panics if the token is not a keyword. + pub fn keyword_syntax(&self) -> &'static str { + use Token::*; + + match self { + LeftBrace => "{", + RightBrace => "}", + LeftParen => "(", + RightParen => ")", + LeftBracket => "[", + RightBracket => "]", + Plus => "+", + UnaryPlus => "+", + Minus => "-", + UnaryMinus => "-", + Multiply => "*", + Divide => "/", + SemiColon => ";", + Colon => ":", + DoubleColon => "::", + DoubleArrow => "=>", + Underscore => "_", + Comma => ",", + Period => ".", + MapStart => "#{", + Equals => "=", + True => "true", + False => "false", + Let => "let", + Const => "const", + If => "if", + Else => "else", + Switch => "switch", + Do => "do", + While => "while", + Until => "until", + Loop => "loop", + For => "for", + In => "in", + LessThan => "<", + GreaterThan => ">", + Bang => "!", + LessThanEqualsTo => "<=", + GreaterThanEqualsTo => ">=", + EqualsTo => "==", + NotEqualsTo => "!=", + Pipe => "|", + Or => "||", + Ampersand => "&", + And => "&&", + Continue => "continue", + Break => "break", + Return => "return", + Throw => "throw", + Try => "try", + Catch => "catch", + PlusAssign => "+=", + MinusAssign => "-=", + MultiplyAssign => "*=", + DivideAssign => "/=", + LeftShiftAssign => "<<=", + RightShiftAssign => ">>=", + AndAssign => "&=", + OrAssign => "|=", + XOrAssign => "^=", + LeftShift => "<<", + RightShift => ">>", + XOr => "^", + Modulo => "%", + ModuloAssign => "%=", + PowerOf => "**", + PowerOfAssign => "**=", + + #[cfg(not(feature = "no_function"))] + Fn => "fn", + #[cfg(not(feature = "no_function"))] + Private => "private", + + #[cfg(not(feature = "no_module"))] + Import => "import", + #[cfg(not(feature = "no_module"))] + Export => "export", + #[cfg(not(feature = "no_module"))] + As => "as", + + t => unreachable!("{:?} is not a keyword", t), + } + } + /// Get the syntax of the token. pub fn syntax(&self) -> Cow<'static, str> { use Token::*; @@ -399,90 +492,9 @@ impl Token { LexError(err) => err.to_string().into(), Comment(s) => s.clone().into(), - token => match token { - LeftBrace => "{", - RightBrace => "}", - LeftParen => "(", - RightParen => ")", - LeftBracket => "[", - RightBracket => "]", - Plus => "+", - UnaryPlus => "+", - Minus => "-", - UnaryMinus => "-", - Multiply => "*", - Divide => "/", - SemiColon => ";", - Colon => ":", - DoubleColon => "::", - DoubleArrow => "=>", - Underscore => "_", - Comma => ",", - Period => ".", - MapStart => "#{", - Equals => "=", - True => "true", - False => "false", - Let => "let", - Const => "const", - If => "if", - Else => "else", - Switch => "switch", - Do => "do", - While => "while", - Until => "until", - Loop => "loop", - For => "for", - In => "in", - LessThan => "<", - GreaterThan => ">", - Bang => "!", - LessThanEqualsTo => "<=", - GreaterThanEqualsTo => ">=", - EqualsTo => "==", - NotEqualsTo => "!=", - Pipe => "|", - Or => "||", - Ampersand => "&", - And => "&&", - Continue => "continue", - Break => "break", - Return => "return", - Throw => "throw", - Try => "try", - Catch => "catch", - PlusAssign => "+=", - MinusAssign => "-=", - MultiplyAssign => "*=", - DivideAssign => "/=", - LeftShiftAssign => "<<=", - RightShiftAssign => ">>=", - AndAssign => "&=", - OrAssign => "|=", - XOrAssign => "^=", - LeftShift => "<<", - RightShift => ">>", - XOr => "^", - Modulo => "%", - ModuloAssign => "%=", - PowerOf => "**", - PowerOfAssign => "**=", + EOF => "{EOF}".into(), - #[cfg(not(feature = "no_function"))] - Fn => "fn", - #[cfg(not(feature = "no_function"))] - Private => "private", - - #[cfg(not(feature = "no_module"))] - Import => "import", - #[cfg(not(feature = "no_module"))] - Export => "export", - #[cfg(not(feature = "no_module"))] - As => "as", - EOF => "{EOF}", - t => unreachable!("operator should be matched in outer scope: {:?}", t), - } - .into(), + token => token.keyword_syntax().into(), } } diff --git a/src/utils.rs b/src/utils.rs index 6be824bf..60fa7e0f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,6 +6,7 @@ use crate::stdlib::{ borrow::Borrow, boxed::Box, cmp::Ordering, + collections::BTreeSet, fmt, fmt::{Debug, Display}, hash::{BuildHasher, Hash, Hasher}, @@ -70,7 +71,11 @@ pub fn get_hasher() -> ahash::AHasher { /// /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline(always)] -pub fn calc_fn_hash<'a>(modules: impl Iterator, fn_name: &str, num: usize) -> u64 { +pub fn calc_fn_hash<'a>( + modules: impl Iterator, + fn_name: impl AsRef, + num: usize, +) -> u64 { let s = &mut get_hasher(); // We always skip the first module @@ -80,7 +85,7 @@ pub fn calc_fn_hash<'a>(modules: impl Iterator, fn_name: &str, n .skip(1) .for_each(|m| m.hash(s)); len.hash(s); - fn_name.hash(s); + fn_name.as_ref().hash(s); num.hash(s); s.finish() } @@ -137,7 +142,7 @@ pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 { /// assert_ne!(s2.as_str(), s.as_str()); /// assert_eq!(s, "hello, world!"); /// ``` -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)] +#[derive(Clone, Eq, Ord, Hash, Default)] pub struct ImmutableString(Shared); impl Deref for ImmutableString { @@ -156,6 +161,13 @@ impl AsRef for ImmutableString { } } +impl AsRef for ImmutableString { + #[inline(always)] + fn as_ref(&self) -> &str { + &self.0 + } +} + impl Borrow for ImmutableString { #[inline(always)] fn borrow(&self) -> &String { @@ -559,7 +571,6 @@ impl PartialEq for String { } impl> PartialOrd for ImmutableString { - #[inline(always)] fn partial_cmp(&self, other: &S) -> Option { self.as_str().partial_cmp(other.as_ref()) } @@ -594,3 +605,19 @@ impl ImmutableString { shared_make_mut(&mut self.0) } } + +/// A collection of interned strings. +#[derive(Debug, Clone, Default, Hash)] +pub struct StringInterner(BTreeSet); + +impl StringInterner { + /// Get an interned string, creating one if it is not yet interned. + #[inline(always)] + pub fn get(&mut self, text: impl AsRef + Into) -> ImmutableString { + self.0.get(text.as_ref()).cloned().unwrap_or_else(|| { + let s = text.into(); + self.0.insert(s.clone()); + s + }) + } +} diff --git a/tests/plugins_unroll.rs b/tests/plugins_unroll.rs index 9003e530..d94a7282 100644 --- a/tests/plugins_unroll.rs +++ b/tests/plugins_unroll.rs @@ -34,7 +34,7 @@ macro_rules! register_in_bulk { { let type_str = stringify!($type_names); set_exported_fn!($mod_name, - format!(concat!(stringify!($op_name), "_{}"), type_str), + &format!(concat!(stringify!($op_name), "_{}"), type_str), crate::$op_name::$type_names::op); } )*