From aa0594210c3e97d3548ee0437f243fab30437fa9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Mar 2021 10:30:30 +0800 Subject: [PATCH 01/11] Use RhaiResult for plugin return. --- Cargo.toml | 2 +- codegen/Cargo.toml | 4 ++-- codegen/src/function.rs | 2 +- codegen/src/test/function.rs | 16 ++++++------- codegen/src/test/module.rs | 44 ++++++++++++++++++------------------ src/plugin.rs | 2 +- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1719c147..264e1b2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"] smallvec = { version = "1.6", default-features = false, features = ["union"] } ahash = { version = "0.6", default-features = false } num-traits = { version = "0.2", default_features = false } -rhai_codegen = { version = "0.3.3", path = "codegen" } +rhai_codegen = { version = "0.3.4", path = "codegen" } [features] default = [] diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 7bcdb878..e4b69a7e 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai_codegen" -version = "0.3.3" +version = "0.3.4" edition = "2018" authors = ["jhwgh1968"] description = "Procedural macro support package for Rhai, a scripting language for Rust" @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" proc-macro = true [dev-dependencies] -rhai = { path = ".." } +rhai = { path = "..", version = "0.19.15" } trybuild = "1" [dependencies] diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 7fef7f42..e1b23264 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -908,7 +908,7 @@ impl ExportedFn { let type_name = syn::Ident::new(on_type_name, proc_macro2::Span::call_site()); quote! { impl PluginFunction for #type_name { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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 diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 58c2613a..9a25b68a 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -277,7 +277,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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())) @@ -331,7 +331,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -386,7 +386,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -444,7 +444,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); Ok(return_dynamic()) @@ -494,7 +494,7 @@ mod generate_tests { let expected_tokens = quote! { impl PluginFunction for TestStruct { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -532,7 +532,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -589,7 +589,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -652,7 +652,7 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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(); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 79f6f872..90cbedc2 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -304,7 +304,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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())) @@ -378,7 +378,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_one_to_token(); impl PluginFunction for add_one_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -452,7 +452,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_one_to_token(); impl PluginFunction for add_one_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -540,7 +540,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_one_to_token(); impl PluginFunction for add_one_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -578,7 +578,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_n_to_token(); impl PluginFunction for add_n_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -655,7 +655,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_together_token(); impl PluginFunction for add_together_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -739,7 +739,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_together_token(); impl PluginFunction for add_together_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -997,7 +997,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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())) @@ -1102,7 +1102,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct print_out_to_token(); impl PluginFunction for print_out_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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(); @@ -1177,7 +1177,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct print_out_to_token(); impl PluginFunction for print_out_to_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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(); @@ -1253,7 +1253,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct foo_token(); impl PluginFunction for foo_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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::(); @@ -1329,7 +1329,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct increment_token(); impl PluginFunction for increment_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1412,7 +1412,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct increment_token(); impl PluginFunction for increment_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1516,7 +1516,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct increment_token(); impl PluginFunction for increment_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1619,7 +1619,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); impl PluginFunction for int_foo_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1701,7 +1701,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); impl PluginFunction for int_foo_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1782,7 +1782,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); impl PluginFunction for int_foo_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1867,7 +1867,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); impl PluginFunction for int_foo_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -1951,7 +1951,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_by_index_token(); impl PluginFunction for get_by_index_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -2041,7 +2041,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_by_index_token(); impl PluginFunction for get_by_index_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -2127,7 +2127,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct set_by_index_token(); impl PluginFunction for set_by_index_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { @@ -2221,7 +2221,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct set_by_index_token(); impl PluginFunction for set_by_index_token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + 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() { diff --git a/src/plugin.rs b/src/plugin.rs index d7013ef7..d33aab73 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -2,11 +2,11 @@ pub use crate::fn_native::{CallableFunction, FnCallArgs}; pub use crate::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString, vec as new_vec}; -use crate::RhaiResult; pub use crate::{ Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, NativeCallContext, Position, }; +pub type RhaiResult = Result>; #[cfg(not(features = "no_module"))] pub use rhai_codegen::*; From 297a5395285e5e71310fa201fa39c66accfc35d7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 20 Mar 2021 23:57:43 +0800 Subject: [PATCH 02/11] Flatten function call arguments. --- src/fn_call.rs | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index c07e5c13..17356679 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -102,21 +102,18 @@ pub fn ensure_no_data_race( args: &FnCallArgs, is_ref: bool, ) -> Result<(), Box> { - if cfg!(not(feature = "no_closure")) { - let skip = if is_ref { 1 } else { 0 }; - - if let Some((n, _)) = args - .iter() - .skip(skip) - .enumerate() - .find(|(_, a)| a.is_locked()) - { - return EvalAltResult::ErrorDataRace( - format!("argument #{} of function '{}'", n + 1 + skip, fn_name), - Position::NONE, - ) - .into(); - } + #[cfg(not(feature = "no_closure"))] + if let Some((n, _)) = args + .iter() + .enumerate() + .skip(if is_ref { 1 } else { 0 }) + .find(|(_, a)| a.is_locked()) + { + return EvalAltResult::ErrorDataRace( + format!("argument #{} of function '{}'", n + 1, fn_name), + Position::NONE, + ) + .into(); } Ok(()) @@ -636,9 +633,8 @@ impl Engine { _level: usize, ) -> Result<(Dynamic, bool), Box> { // Check for data race. - if cfg!(not(feature = "no_closure")) { - ensure_no_data_race(fn_name, args, is_ref)?; - } + #[cfg(not(feature = "no_closure"))] + ensure_no_data_race(fn_name, args, is_ref)?; // These may be redirected from method style calls. match fn_name { @@ -1259,7 +1255,10 @@ impl Engine { arg_values = args_expr .iter() .skip(1) - .map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)) + .map(|expr| { + self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(Dynamic::flatten) + }) .collect::>()?; let (mut target, pos) = @@ -1285,7 +1284,10 @@ impl Engine { // func(..., ...) arg_values = args_expr .iter() - .map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)) + .map(|expr| { + self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(Dynamic::flatten) + }) .collect::>()?; args = curry.iter_mut().chain(arg_values.iter_mut()).collect(); @@ -1340,6 +1342,7 @@ impl Engine { Ok(Default::default()) } else { self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(Dynamic::flatten) } }) .collect::>()?; @@ -1364,7 +1367,10 @@ impl Engine { // func(..., ...) or func(mod::x, ...) arg_values = args_expr .iter() - .map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)) + .map(|expr| { + self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(Dynamic::flatten) + }) .collect::>()?; args = arg_values.iter_mut().collect(); From 673bff7c7611ca17fada9165c4d553e8d61acded Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 21 Mar 2021 22:30:34 +0800 Subject: [PATCH 03/11] Add doc links. --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8d2b90e6..57cc560e 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ Supported targets and builds Standard features ----------------- -* Simple language similar to JavaScript+Rust with dynamic typing. +* Simple language similar to JavaScript+Rust with [dynamic](https://rhai.rs/book/language/dynamic.html) typing. * Fairly efficient evaluation (1 million iterations in 0.3 sec on a single-core, 2.3 GHz Linux VM). * Tight integration with native Rust [functions](https://rhai.rs/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhai.rs/book/rust/custom.html)), including [getters/setters](https://rhai.rs/book/rust/getters-setters.html), [methods](https://rhai.rs/book/rust/custom.html) and [indexers](https://rhai.rs/book/rust/indexers.html). -* Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhai.rs/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. -* Built-in support for most common [data types](https://rhai.rs/book/language/values-and-types.html) including booleans, integers, floating-point numbers (including [`Decimal`](https://crates.io/crates/rust_decimal)), strings, Unicode characters, arrays and maps. +* Freely pass Rust values into a script as [variables](https://rhai.rs/book/language/variables.html)/[constants](https://rhai.rs/book/language/constants.html) via an external [`Scope`](https://rhai.rs/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. Or tap directly into the [variable resolution process](https://rhai.rs/book/engine/var.html). +* Built-in support for most common [data types](https://rhai.rs/book/language/values-and-types.html) including booleans, [integers](https://rhai.rs/book/language/numbers.html), [floating-point numbers](https://rhai.rs/book/language/numbers.html) (including [`Decimal`](https://crates.io/crates/rust_decimal)), [strings](https://rhai.rs/book/language/strings-chars.html), [Unicode characters](https://rhai.rs/book/language/strings-chars.html), [arrays](https://rhai.rs/book/language/arrays.html) and [object maps](https://rhai.rs/book/language/object-maps.html). * Easily [call a script-defined function](https://rhai.rs/book/engine/call-fn.html) from Rust. * Relatively little `unsafe` code (yes there are some for performance reasons). * Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec), [`num-traits`](https://crates.io/crates/num-traits) and [`ahash`](https://crates.io/crates/ahash)). @@ -44,7 +44,7 @@ Standard features * Dynamic dispatch via [function pointers](https://rhai.rs/book/language/fn-ptr.html) with additional support for [currying](https://rhai.rs/book/language/fn-curry.html). * [Closures](https://rhai.rs/book/language/fn-closure.html) (anonymous functions) that can capture shared values. * Some syntactic support for [object-oriented programming (OOP)](https://rhai.rs/book/language/oop.html). -* Organize code base with dynamically-loadable [modules](https://rhai.rs/book/language/modules.html), optionally overriding the resolution process +* Organize code base with dynamically-loadable [modules](https://rhai.rs/book/language/modules.html), optionally [overriding the resolution process](https://rhai.rs/book/rust/modules/resolvers.html). * Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature). * Support for [minimal builds](https://rhai.rs/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhai.rs/book/start/features.html). @@ -52,7 +52,8 @@ Standard features Protected against attacks ------------------------- -* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhai.rs/book/patterns/control.html). +* _Don't Panic_ guarantee - Any panic is a bug. Rhai subscribes to the motto that a library should never panic the host system, and is coded with this in mind. +* [Sand-boxed](https://rhai.rs/book/safety/sandbox.html) - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhai.rs/book/patterns/control.html). * Rugged - protected against malicious attacks (such as [stack-overflow](https://rhai.rs/book/safety/max-call-stack.html), [over-sized data](https://rhai.rs/book/safety/max-string-size.html), and [runaway scripts](https://rhai.rs/book/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts. * Track script evaluation [progress](https://rhai.rs/book/safety/progress.html) and manually terminate a script run. @@ -75,14 +76,14 @@ Project Site Documentation ------------- -See [The Rhai Book](https://rhai.rs/book) for details on the Rhai scripting engine and language. +See [_The Rhai Book_](https://rhai.rs/book) for details on the Rhai scripting engine and language. Playground ---------- -An [Online Playground](https://rhai.rs/playground) is available with -syntax-highlighting editor, powered by WebAssembly. +An [_Online Playground_](https://rhai.rs/playground) is available with syntax-highlighting editor, +powered by WebAssembly. Scripts can be evaluated directly from the editor. From 75b8bf73dfe283281b2b4c5506ad43ae0345ded7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 21 Mar 2021 23:51:24 +0800 Subject: [PATCH 04/11] Update dependencies. --- Cargo.toml | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 264e1b2a..c95fc996 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,30 +17,29 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"] [dependencies] smallvec = { version = "1.6", default-features = false, features = ["union"] } -ahash = { version = "0.6", default-features = false } +ahash = { version = "0.7", default-features = false } num-traits = { version = "0.2", default_features = false } rhai_codegen = { version = "0.3.4", path = "codegen" } [features] default = [] -unchecked = [] # unchecked arithmetic -sync = [] # restrict to only types that implement Send + Sync -no_optimize = [] # no script optimizer -no_float = [] # no floating-point -f32_float = [] # set FLOAT=f32 -only_i32 = [] # set INT=i32 (useful for 32-bit systems) -only_i64 = [] # set INT=i64 (default) and disable support for all other integer types -decimal = ["rust_decimal"] # add the Decimal number type -no_index = [] # no arrays and indexing -no_object = [] # no custom objects -no_function = ["no_closure"] # no script-defined functions (meaning no closures) -no_closure = [] # no automatic sharing and capture of anonymous functions to external variables -no_module = [] # no modules -internals = [] # expose internal data structures +unchecked = [] # unchecked arithmetic +sync = [] # restrict to only types that implement Send + Sync +no_optimize = [] # no script optimizer +no_float = [] # no floating-point +f32_float = [] # set FLOAT=f32 +only_i32 = [] # set INT=i32 (useful for 32-bit systems) +only_i64 = [] # set INT=i64 (default) and disable support for all other integer types +decimal = ["rust_decimal"] # add the Decimal number type +no_index = [] # no arrays and indexing +no_object = [] # no custom objects +no_function = ["no_closure"] # no script-defined functions (meaning no closures) +no_closure = [] # no automatic sharing and capture of anonymous functions to external variables +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", "serde_json"] # enables exporting functions metadata to JSON -# compiling for no-std no_std = ["smallvec/union", "num-traits/libm", "hashbrown", "core-error", "libm", "ahash/compile-time-rng"] # compiling for WASM @@ -65,7 +64,7 @@ features = ["alloc"] optional = true [dependencies.hashbrown] -version = "0.7" +version = "0.11" default-features = false features = ["ahash", "nightly", "inline-more"] optional = true @@ -99,4 +98,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"] +features = ["metadata", "internals", "decimal"] # compiling for no-std From b3bcd7bf798c01974cbaf094d650b46f73284359 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 10:08:43 +0800 Subject: [PATCH 05/11] Fix codegen test. --- codegen/ui_tests/export_mod_raw_return.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/ui_tests/export_mod_raw_return.stderr b/codegen/ui_tests/export_mod_raw_return.stderr index b2e2668f..2b194c02 100644 --- a/codegen/ui_tests/export_mod_raw_return.stderr +++ b/codegen/ui_tests/export_mod_raw_return.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/export_mod_raw_return.rs:12:8 | 9 | #[export_module] - | ---------------- expected `Result>` because of return type + | ---------------- expected `Result>` because of return type ... 12 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `bool` | - = note: expected enum `Result>` + = note: expected enum `Result>` found type `bool` From a82f0fc738c6d3122b6ce3e404d9b3caaa17bf32 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 11:18:09 +0800 Subject: [PATCH 06/11] Allow non-Dynamic in return_raw. --- CHANGELOG.md | 4 +- codegen/src/function.rs | 33 +------ codegen/src/test/function.rs | 4 +- .../ui_tests/export_fn_raw_noreturn.stderr | 2 +- codegen/ui_tests/export_fn_raw_return.stderr | 13 ++- .../ui_tests/export_mod_raw_noreturn.stderr | 2 +- codegen/ui_tests/export_mod_raw_return.stderr | 14 ++- .../rhai_fn_non_clonable_return.stderr | 2 +- .../rhai_mod_non_clonable_return.stderr | 2 +- src/ast.rs | 2 +- src/dynamic.rs | 55 +++++------ src/engine.rs | 6 -- src/engine_api.rs | 5 +- src/fn_builtin.rs | 2 +- src/fn_func.rs | 5 +- src/lib.rs | 6 +- src/packages/arithmetic.rs | 88 ++++++++--------- src/packages/array_basic.rs | 94 ++++++++----------- src/packages/map_basic.rs | 16 ++-- src/packages/math_basic.rs | 92 ++++++++---------- src/packages/string_more.rs | 8 +- src/packages/time_basic.rs | 35 ++++--- src/unsafe.rs | 6 +- 23 files changed, 214 insertions(+), 282 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d0dd3b4..9055d3df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,14 @@ Breaking changes * 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. Enhancements ------------ -* `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any type. +* `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>`. Version 0.19.14 diff --git a/codegen/src/function.rs b/codegen/src/function.rs index e1b23264..f69ed3cd 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -279,7 +279,6 @@ pub struct ExportedFn { signature: syn::Signature, visibility: syn::Visibility, pass_context: bool, - return_dynamic: bool, mut_receiver: bool, params: ExportedFnParams, } @@ -290,10 +289,6 @@ impl Parse for ExportedFn { let entire_span = fn_all.span(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); - let dynamic_type_path1 = syn::parse2::(quote! { Dynamic }).unwrap(); - let dynamic_type_path2 = syn::parse2::(quote! { rhai::Dynamic }).unwrap(); - let mut return_dynamic = false; - let context_type_path1 = syn::parse2::(quote! { NativeCallContext }).unwrap(); let context_type_path2 = syn::parse2::(quote! { rhai::NativeCallContext }).unwrap(); @@ -400,11 +395,6 @@ impl Parse for ExportedFn { "Rhai functions cannot return references", )) } - syn::Type::Path(p) - if p.path == dynamic_type_path1 || p.path == dynamic_type_path2 => - { - return_dynamic = true - } _ => {} } } @@ -413,7 +403,6 @@ impl Parse for ExportedFn { signature: fn_all.sig, visibility, pass_context, - return_dynamic, mut_receiver, params: Default::default(), }) @@ -520,7 +509,7 @@ impl ExportedFn { if params.return_raw.is_some() && self.return_type().is_none() { return Err(syn::Error::new( params.return_raw.unwrap(), - "functions marked with 'return_raw' must return Result>", + "functions marked with 'return_raw' must return Result>", )); } @@ -656,13 +645,7 @@ impl ExportedFn { if self.params.return_raw.is_some() { quote_spanned! { return_span => pub #dynamic_signature { - #name(#(#arguments),*) - } - } - } else if self.return_dynamic { - quote_spanned! { return_span => - pub #dynamic_signature { - Ok(#name(#(#arguments),*)) + #name(#(#arguments),*).map(Dynamic::from) } } } else { @@ -890,18 +873,12 @@ impl ExportedFn { .map(|r| r.span()) .unwrap_or_else(|| proc_macro2::Span::call_site()); let return_expr = if !self.params.return_raw.is_some() { - if self.return_dynamic { - quote_spanned! { return_span => - Ok(#sig_name(#(#unpack_exprs),*)) - } - } else { - quote_spanned! { return_span => - Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*))) - } + quote_spanned! { return_span => + Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*))) } } else { quote_spanned! { return_span => - #sig_name(#(#unpack_exprs),*) + #sig_name(#(#unpack_exprs),*).map(Dynamic::from) } }; diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 9a25b68a..25a0886a 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -447,7 +447,7 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); - Ok(return_dynamic()) + Ok(Dynamic::from(return_dynamic())) } fn is_method_call(&self) -> bool { false } @@ -477,7 +477,7 @@ mod generate_tests { } #[allow(unused)] pub fn dynamic_result_fn() -> Result > { - Ok(return_dynamic()) + Ok(Dynamic::from(return_dynamic())) } } }; diff --git a/codegen/ui_tests/export_fn_raw_noreturn.stderr b/codegen/ui_tests/export_fn_raw_noreturn.stderr index d4a992c0..51df546a 100644 --- a/codegen/ui_tests/export_fn_raw_noreturn.stderr +++ b/codegen/ui_tests/export_fn_raw_noreturn.stderr @@ -1,4 +1,4 @@ -error: functions marked with 'return_raw' must return Result> +error: functions marked with 'return_raw' must return Result> --> $DIR/export_fn_raw_noreturn.rs:9:13 | 9 | #[export_fn(return_raw)] diff --git a/codegen/ui_tests/export_fn_raw_return.stderr b/codegen/ui_tests/export_fn_raw_return.stderr index 65ebcd8b..3dc04fa8 100644 --- a/codegen/ui_tests/export_fn_raw_return.stderr +++ b/codegen/ui_tests/export_fn_raw_return.stderr @@ -1,10 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/export_fn_raw_return.rs:10:8 +error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied + --> $DIR/export_fn_raw_return.rs:10:33 | -9 | #[export_fn(return_raw)] - | ------------------------ expected `Result>` because of return type 10 | pub fn test_fn(input: Point) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `bool` + | ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds | - = note: expected enum `Result>` - found type `bool` + = note: the following trait bounds were not satisfied: + `bool: std::iter::Iterator` + which is required by `&mut bool: std::iter::Iterator` diff --git a/codegen/ui_tests/export_mod_raw_noreturn.stderr b/codegen/ui_tests/export_mod_raw_noreturn.stderr index d59be0f8..71945f4a 100644 --- a/codegen/ui_tests/export_mod_raw_noreturn.stderr +++ b/codegen/ui_tests/export_mod_raw_noreturn.stderr @@ -1,4 +1,4 @@ -error: functions marked with 'return_raw' must return Result> +error: functions marked with 'return_raw' must return Result> --> $DIR/export_mod_raw_noreturn.rs:11:11 | 11 | #[rhai_fn(return_raw)] diff --git a/codegen/ui_tests/export_mod_raw_return.stderr b/codegen/ui_tests/export_mod_raw_return.stderr index 2b194c02..d62b9d94 100644 --- a/codegen/ui_tests/export_mod_raw_return.stderr +++ b/codegen/ui_tests/export_mod_raw_return.stderr @@ -1,11 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/export_mod_raw_return.rs:12:8 +error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied + --> $DIR/export_mod_raw_return.rs:12:33 | -9 | #[export_module] - | ---------------- expected `Result>` because of return type -... 12 | pub fn test_fn(input: Point) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `bool` + | ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds | - = note: expected enum `Result>` - found type `bool` + = note: the following trait bounds were not satisfied: + `bool: std::iter::Iterator` + which is required by `&mut bool: std::iter::Iterator` diff --git a/codegen/ui_tests/rhai_fn_non_clonable_return.stderr b/codegen/ui_tests/rhai_fn_non_clonable_return.stderr index 73d02b28..b9016a12 100644 --- a/codegen/ui_tests/rhai_fn_non_clonable_return.stderr +++ b/codegen/ui_tests/rhai_fn_non_clonable_return.stderr @@ -6,5 +6,5 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied | ::: $WORKSPACE/src/dynamic.rs | - | pub fn from(value: T) -> Self { + | pub fn from(mut value: T) -> Self { | ----- required by this bound in `rhai::Dynamic::from` diff --git a/codegen/ui_tests/rhai_mod_non_clonable_return.stderr b/codegen/ui_tests/rhai_mod_non_clonable_return.stderr index e7860394..900efa16 100644 --- a/codegen/ui_tests/rhai_mod_non_clonable_return.stderr +++ b/codegen/ui_tests/rhai_mod_non_clonable_return.stderr @@ -6,5 +6,5 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied | ::: $WORKSPACE/src/dynamic.rs | - | pub fn from(value: T) -> Self { + | pub fn from(mut value: T) -> Self { | ----- required by this bound in `rhai::Dynamic::from` diff --git a/src/ast.rs b/src/ast.rs index 39a5796a..5ca155a4 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1303,7 +1303,7 @@ pub struct OpAssignment { /// /// Two separate hashes are pre-calculated because of the following pattern: /// -/// ```,ignore +/// ```ignore /// func(a, b, c); // Native: func(a, b, c) - 3 parameters /// // Script: func(a, b, c) - 3 parameters /// diff --git a/src/dynamic.rs b/src/dynamic.rs index b6bb5e71..4b52e89e 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -833,9 +833,13 @@ impl Dynamic { /// assert_eq!(new_result.to_string(), "hello"); /// ``` #[inline(always)] - pub fn from(value: T) -> Self { + pub fn from(mut value: T) -> Self { // Coded this way in order to maximally leverage potentials for dead-code removal. + if TypeId::of::() == TypeId::of::() { + return unsafe_try_cast::<_, Dynamic>(value).ok().unwrap(); + } + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() @@ -884,46 +888,43 @@ impl Dynamic { return ().into(); } - let mut boxed = Box::new(value); - - boxed = match unsafe_cast_box::<_, Dynamic>(boxed) { - Ok(d) => return *d, - Err(val) => val, - }; - boxed = match unsafe_cast_box::<_, String>(boxed) { - Ok(s) => return (*s).into(), + value = match unsafe_try_cast::<_, String>(value) { + Ok(s) => return (s).into(), Err(val) => val, }; #[cfg(not(feature = "no_index"))] { - boxed = match unsafe_cast_box::<_, Array>(boxed) { - Ok(array) => return (*array).into(), + value = match unsafe_try_cast::<_, Array>(value) { + Ok(array) => return (array).into(), Err(val) => val, }; } #[cfg(not(feature = "no_object"))] { - boxed = match unsafe_cast_box::<_, Map>(boxed) { - Ok(map) => return (*map).into(), + value = match unsafe_try_cast::<_, Map>(value) { + Ok(map) => return (map).into(), Err(val) => val, } } - boxed = match unsafe_cast_box::<_, FnPtr>(boxed) { - Ok(fn_ptr) => return (*fn_ptr).into(), + value = match unsafe_try_cast::<_, FnPtr>(value) { + Ok(fn_ptr) => return (fn_ptr).into(), Err(val) => val, }; #[cfg(not(feature = "no_std"))] { - boxed = match unsafe_cast_box::<_, Instant>(boxed) { - Ok(timestamp) => return (*timestamp).into(), + value = match unsafe_try_cast::<_, Instant>(value) { + Ok(timestamp) => return (timestamp).into(), Err(val) => val, } } - Self(Union::Variant(Box::new(boxed), AccessMode::ReadWrite)) + Self(Union::Variant( + Box::new(Box::new(value)), + AccessMode::ReadWrite, + )) } /// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an /// [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>` or @@ -986,12 +987,12 @@ impl Dynamic { } if TypeId::of::() == TypeId::of::() { - return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v); + return unsafe_try_cast::<_, T>(self).ok(); } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Int(value, _) => unsafe_try_cast(value), + Union::Int(value, _) => unsafe_try_cast(value).ok(), _ => None, }; } @@ -999,7 +1000,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Float(value, _) => unsafe_try_cast(*value), + Union::Float(value, _) => unsafe_try_cast(*value).ok(), _ => None, }; } @@ -1007,35 +1008,35 @@ impl Dynamic { #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Decimal(value, _) => unsafe_try_cast(*value), + Union::Decimal(value, _) => unsafe_try_cast(*value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Bool(value, _) => unsafe_try_cast(value), + Union::Bool(value, _) => unsafe_try_cast(value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _) => unsafe_try_cast(value), + Union::Str(value, _) => unsafe_try_cast(value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _) => unsafe_try_cast(value.into_owned()), + Union::Str(value, _) => unsafe_try_cast(value.into_owned()).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Char(value, _) => unsafe_try_cast(value), + Union::Char(value, _) => unsafe_try_cast(value).ok(), _ => None, }; } @@ -1073,7 +1074,7 @@ impl Dynamic { if TypeId::of::() == TypeId::of::<()>() { return match self.0 { - Union::Unit(value, _) => unsafe_try_cast(value), + Union::Unit(value, _) => unsafe_try_cast(value).ok(), _ => None, }; } diff --git a/src/engine.rs b/src/engine.rs index 4061431c..b2a3dcfb 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1047,12 +1047,6 @@ impl Engine { let val = scope.get_mut_by_index(index); - // Check for data race - probably not necessary because the only place it should conflict is - // in a method call when the object variable is also used as a parameter. - // if cfg!(not(feature = "no_closure")) && val.is_locked() { - // return EvalAltResult::ErrorDataRace(name.into(), *pos).into(); - // } - Ok((val.into(), *pos)) } diff --git a/src/engine_api.rs b/src/engine_api.rs index 6900a268..1f80b747 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1885,9 +1885,8 @@ impl Engine { .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?; // Check for data race. - if cfg!(not(feature = "no_closure")) { - crate::fn_call::ensure_no_data_race(name, args, false)?; - } + #[cfg(not(feature = "no_closure"))] + crate::fn_call::ensure_no_data_race(name, args, false)?; self.call_script_fn( scope, diff --git a/src/fn_builtin.rs b/src/fn_builtin.rs index c592bb0e..828de6fb 100644 --- a/src/fn_builtin.rs +++ b/src/fn_builtin.rs @@ -109,7 +109,7 @@ pub fn get_builtin_binary_op_fn( return Some(|_, args| { let x = args[0].$xx().unwrap() as $base; let y = args[1].$yy().unwrap() as $base; - $func(x, y) + $func(x, y).map(Into::::into) }) }; (from $base:ty => $xx:ident $op:tt $yy:ident) => { diff --git a/src/fn_func.rs b/src/fn_func.rs index a9576989..93c036ff 100644 --- a/src/fn_func.rs +++ b/src/fn_func.rs @@ -98,10 +98,7 @@ macro_rules! def_anonymous_fn { #[inline(always)] fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output { let fn_name = entry_point.to_string(); - - Box::new(move |$($par: $par),*| { - self.call_fn(&mut Scope::new(), &ast, &fn_name, ($($par,)*)) - }) + Box::new(move |$($par),*| self.call_fn(&mut Scope::new(), &ast, &fn_name, ($($par,)*))) } #[inline(always)] diff --git a/src/lib.rs b/src/lib.rs index 0b34b4af..982f3e01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ //! //! ## Contents of `my_script.rhai` //! -//! ```,ignore +//! ```ignore //! /// Brute force factorial function //! fn factorial(x) { //! if x == 1 { return 1; } @@ -24,7 +24,7 @@ //! //! ## The Rust part //! -//! ```,no_run +//! ```no_run //! use rhai::{Engine, EvalAltResult}; //! //! fn main() -> Result<(), Box> @@ -88,7 +88,7 @@ mod token; mod r#unsafe; mod utils; -type RhaiResult = Result>; +type RhaiResult = stdlib::result::Result>; /// The system integer type. It is defined as [`i64`]. /// diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index 0c96a6af..1844dc66 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -24,91 +24,91 @@ macro_rules! gen_arithmetic_functions { #[export_module] pub mod functions { #[rhai_fn(name = "+", return_raw)] - pub fn add(x: $arg_type, y: $arg_type) -> Result> { + pub fn add(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_add(y).ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))).map(Dynamic::from) + x.checked_add(y).ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))) } else { - Ok(Dynamic::from(x + y)) + Ok(x + y) } } #[rhai_fn(name = "-", return_raw)] - pub fn subtract(x: $arg_type, y: $arg_type) -> Result> { + pub fn subtract(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_sub(y).ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))).map(Dynamic::from) + x.checked_sub(y).ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))) } else { - Ok(Dynamic::from(x - y)) + Ok(x - y) } } #[rhai_fn(name = "*", return_raw)] - pub fn multiply(x: $arg_type, y: $arg_type) -> Result> { + pub fn multiply(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_mul(y).ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))).map(Dynamic::from) + x.checked_mul(y).ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))) } else { - Ok(Dynamic::from(x * y)) + Ok(x * y) } } #[rhai_fn(name = "/", return_raw)] - pub fn divide(x: $arg_type, y: $arg_type) -> Result> { + pub fn divide(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { // Detect division by zero if y == 0 { Err(make_err(format!("Division by zero: {} / {}", x, y))) } else { - x.checked_div(y).ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y))).map(Dynamic::from) + x.checked_div(y).ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y))) } } else { - Ok(Dynamic::from(x / y)) + Ok(x / y) } } #[rhai_fn(name = "%", return_raw)] - pub fn modulo(x: $arg_type, y: $arg_type) -> Result> { + pub fn modulo(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_rem(y).ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {} % {}", x, y))).map(Dynamic::from) + x.checked_rem(y).ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {} % {}", x, y))) } else { - Ok(Dynamic::from(x % y)) + Ok(x % y) } } #[rhai_fn(name = "**", return_raw)] - pub fn power(x: INT, y: INT) -> Result> { + pub fn power(x: $arg_type, y: INT) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) { Err(make_err(format!("Integer raised to too large an index: {} ~ {}", x, y))) } else if y < 0 { Err(make_err(format!("Integer raised to a negative index: {} ~ {}", x, y))) } else { - x.checked_pow(y as u32).ok_or_else(|| make_err(format!("Power overflow: {} ~ {}", x, y))).map(Dynamic::from) + x.checked_pow(y as u32).ok_or_else(|| make_err(format!("Power overflow: {} ~ {}", x, y))) } } else { - Ok(Dynamic::from(x.pow(y as u32))) + Ok(x.pow(y as u32)) } } #[rhai_fn(name = "<<", return_raw)] - pub fn shift_left(x: $arg_type, y: INT) -> Result> { + pub fn shift_left(x: $arg_type, y: INT) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) { Err(make_err(format!("Left-shift by too many bits: {} << {}", x, y))) } else if y < 0 { Err(make_err(format!("Left-shift by a negative number: {} << {}", x, y))) } else { - x.checked_shl(y as u32).ok_or_else(|| make_err(format!("Left-shift by too many bits: {} << {}", x, y))).map(Dynamic::from) + x.checked_shl(y as u32).ok_or_else(|| make_err(format!("Left-shift by too many bits: {} << {}", x, y))) } } else { - Ok(Dynamic::from(x << y)) + Ok(x << y) } } #[rhai_fn(name = ">>", return_raw)] - pub fn shift_right(x: $arg_type, y: INT) -> Result> { + pub fn shift_right(x: $arg_type, y: INT) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) { Err(make_err(format!("Right-shift by too many bits: {} >> {}", x, y))) } else if y < 0 { Err(make_err(format!("Right-shift by a negative number: {} >> {}", x, y))) } else { - x.checked_shr(y as u32).ok_or_else(|| make_err(format!("Right-shift by too many bits: {} >> {}", x, y))).map(Dynamic::from) + x.checked_shr(y as u32).ok_or_else(|| make_err(format!("Right-shift by too many bits: {} >> {}", x, y))) } } else { - Ok(Dynamic::from(x >> y)) + Ok(x >> y) } } #[rhai_fn(name = "&")] @@ -136,11 +136,11 @@ macro_rules! gen_signed_functions { #[export_module] pub mod functions { #[rhai_fn(name = "-", return_raw)] - pub fn neg(x: $arg_type) -> Result> { + pub fn neg(x: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_neg().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))).map(Dynamic::from) + x.checked_neg().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))) } else { - Ok(Dynamic::from(-x)) + Ok(-x) } } #[rhai_fn(name = "+")] @@ -148,11 +148,11 @@ macro_rules! gen_signed_functions { x } #[rhai_fn(return_raw)] - pub fn abs(x: $arg_type) -> Result> { + pub fn abs(x: $arg_type) -> Result<$arg_type, Box> { if cfg!(not(feature = "unchecked")) { - x.checked_abs().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))).map(Dynamic::from) + x.checked_abs().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))) } else { - Ok(Dynamic::from(x.abs())) + Ok(x.abs()) } } pub fn sign(x: $arg_type) -> INT { @@ -318,14 +318,14 @@ mod f32_functions { } } #[rhai_fn(name = "**", return_raw)] - pub fn pow_f_i(x: f32, y: INT) -> Result> { + pub fn pow_f_i(x: f32, y: INT) -> Result> { if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) { Err(make_err(format!( "Number raised to too large an index: {} ~ {}", x, y ))) } else { - Ok(Dynamic::from(x.powi(y as i32))) + Ok(x.powi(y as i32)) } } } @@ -423,14 +423,14 @@ mod f64_functions { } } #[rhai_fn(name = "**", return_raw)] - pub fn pow_f_i(x: FLOAT, y: INT) -> Result> { + pub fn pow_f_i(x: FLOAT, y: INT) -> Result> { if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) { Err(make_err(format!( "Number raised to too large an index: {} ~ {}", x, y ))) } else { - Ok(x.powi(y as i32).into()) + Ok(x.powi(y as i32)) } } } @@ -441,37 +441,37 @@ pub mod decimal_functions { use rust_decimal::{prelude::Zero, Decimal}; #[rhai_fn(skip, return_raw)] - pub fn add(x: Decimal, y: Decimal) -> Result> { + pub fn add(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { x.checked_add(y) .ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))) .map(Into::::into) } else { - Ok(Dynamic::from(x + y)) + Ok(x + y) } } #[rhai_fn(skip, return_raw)] - pub fn subtract(x: Decimal, y: Decimal) -> Result> { + pub fn subtract(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { x.checked_sub(y) .ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))) .map(Into::::into) } else { - Ok(Dynamic::from(x - y)) + Ok(x - y) } } #[rhai_fn(skip, return_raw)] - pub fn multiply(x: Decimal, y: Decimal) -> Result> { + pub fn multiply(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { x.checked_mul(y) .ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))) .map(Into::::into) } else { - Ok(Dynamic::from(x * y)) + Ok(x * y) } } #[rhai_fn(skip, return_raw)] - pub fn divide(x: Decimal, y: Decimal) -> Result> { + pub fn divide(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { // Detect division by zero if y == Decimal::zero() { @@ -482,11 +482,11 @@ pub mod decimal_functions { .map(Into::::into) } } else { - Ok(Dynamic::from(x / y)) + Ok(x / y) } } #[rhai_fn(skip, return_raw)] - pub fn modulo(x: Decimal, y: Decimal) -> Result> { + pub fn modulo(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { x.checked_rem(y) .ok_or_else(|| { @@ -497,7 +497,7 @@ pub mod decimal_functions { }) .map(Into::::into) } else { - Ok(Dynamic::from(x % y)) + Ok(x % y) } } #[rhai_fn(name = "-")] diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 5244c46d..0c4701a7 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -47,7 +47,7 @@ mod array_functions { array: &mut Array, len: INT, item: Dynamic, - ) -> Result> { + ) -> Result<(), Box> { // Check if array will be over max size limit #[cfg(not(feature = "unchecked"))] if _ctx.engine().max_array_size() > 0 @@ -62,7 +62,7 @@ mod array_functions { array.resize(len as usize, item); } - Ok(Dynamic::UNIT) + Ok(()) } pub fn pop(array: &mut Array) -> Dynamic { array.pop().unwrap_or_else(|| ().into()) @@ -169,7 +169,7 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, mapper: FnPtr, - ) -> Result> { + ) -> Result> { let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); for (i, item) in array.iter().enumerate() { @@ -195,14 +195,14 @@ mod array_functions { ); } - Ok(ar.into()) + Ok(ar) } #[rhai_fn(return_raw, pure)] pub fn filter( ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); for (i, item) in array.iter().enumerate() { @@ -231,14 +231,14 @@ mod array_functions { } } - Ok(ar.into()) + Ok(ar) } #[rhai_fn(return_raw, pure)] pub fn contains( ctx: NativeCallContext, array: &mut Array, value: Dynamic, - ) -> Result> { + ) -> Result> { for item in array.iter_mut() { if ctx .call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()]) @@ -258,18 +258,18 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok(Dynamic::TRUE); + return Ok(true); } } - Ok(Dynamic::FALSE) + Ok(false) } #[rhai_fn(return_raw, pure)] pub fn index_of( ctx: NativeCallContext, array: &mut Array, value: Dynamic, - ) -> Result> { + ) -> Result> { for (i, item) in array.iter_mut().enumerate() { if ctx .call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()]) @@ -289,18 +289,18 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok((i as INT).into()); + return Ok(i as INT); } } - Ok((-1 as INT).into()) + Ok(-1 as INT) } #[rhai_fn(name = "index_of", return_raw, pure)] pub fn index_of_filter( ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { for (i, item) in array.iter().enumerate() { if filter .call_dynamic(&ctx, None, [item.clone()]) @@ -323,18 +323,18 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok((i as INT).into()); + return Ok(i as INT); } } - Ok((-1 as INT).into()) + Ok(-1 as INT) } #[rhai_fn(return_raw, pure)] pub fn some( ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { for (i, item) in array.iter().enumerate() { if filter .call_dynamic(&ctx, None, [item.clone()]) @@ -357,18 +357,18 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok(true.into()); + return Ok(true); } } - Ok(false.into()) + Ok(false) } #[rhai_fn(return_raw, pure)] pub fn all( ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { for (i, item) in array.iter().enumerate() { if !filter .call_dynamic(&ctx, None, [item.clone()]) @@ -391,11 +391,11 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok(false.into()); + return Ok(false); } } - Ok(true.into()) + Ok(true) } #[rhai_fn(return_raw, pure)] pub fn reduce( @@ -403,7 +403,7 @@ mod array_functions { array: &mut Array, reducer: FnPtr, ) -> Result> { - let mut result: Dynamic = Dynamic::UNIT; + let mut result = Dynamic::UNIT; for (i, item) in array.iter().enumerate() { result = reducer @@ -433,16 +433,9 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, reducer: FnPtr, - initial: FnPtr, + initial: Dynamic, ) -> Result> { - let mut result = initial.call_dynamic(&ctx, None, []).map_err(|err| { - Box::new(EvalAltResult::ErrorInFunctionCall( - "reduce".to_string(), - ctx.source().unwrap_or("").to_string(), - err, - Position::NONE, - )) - })?; + let mut result = initial; for (i, item) in array.iter().enumerate() { result = reducer @@ -473,7 +466,7 @@ mod array_functions { array: &mut Array, reducer: FnPtr, ) -> Result> { - let mut result: Dynamic = Dynamic::UNIT; + let mut result = Dynamic::UNIT; for (i, item) in array.iter().enumerate().rev() { result = reducer @@ -503,16 +496,9 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, reducer: FnPtr, - initial: FnPtr, + initial: Dynamic, ) -> Result> { - let mut result = initial.call_dynamic(&ctx, None, []).map_err(|err| { - Box::new(EvalAltResult::ErrorInFunctionCall( - "reduce_rev".to_string(), - ctx.source().unwrap_or("").to_string(), - err, - Position::NONE, - )) - })?; + let mut result = initial; for (i, item) in array.iter().enumerate().rev() { result = reducer @@ -542,7 +528,7 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, comparer: FnPtr, - ) -> Result> { + ) -> Result<(), Box> { array.sort_by(|x, y| { comparer .call_dynamic(&ctx, None, [x.clone(), y.clone()]) @@ -571,14 +557,14 @@ mod array_functions { }) }); - Ok(Dynamic::UNIT) + Ok(()) } #[rhai_fn(return_raw)] pub fn drain( ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); let mut i = array.len(); @@ -611,7 +597,7 @@ mod array_functions { } } - Ok(drained.into()) + Ok(drained) } #[rhai_fn(name = "drain")] pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array { @@ -638,7 +624,7 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, filter: FnPtr, - ) -> Result> { + ) -> Result> { let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); let mut i = array.len(); @@ -671,7 +657,7 @@ mod array_functions { } } - Ok(drained.into()) + Ok(drained) } #[rhai_fn(name = "retain")] pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array { @@ -701,12 +687,12 @@ mod array_functions { ctx: NativeCallContext, array: &mut Array, mut array2: Array, - ) -> Result> { + ) -> Result> { if array.len() != array2.len() { - return Ok(false.into()); + return Ok(false); } if array.is_empty() { - return Ok(true.into()); + return Ok(true); } for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) { @@ -728,18 +714,18 @@ mod array_functions { .as_bool() .unwrap_or(false) { - return Ok(Dynamic::FALSE); + return Ok(false); } } - Ok(Dynamic::TRUE) + Ok(true) } #[rhai_fn(name = "!=", return_raw, pure)] pub fn not_equals( ctx: NativeCallContext, array: &mut Array, array2: Array, - ) -> Result> { - equals(ctx, array, array2).map(|r| (!r.as_bool().unwrap()).into()) + ) -> Result> { + equals(ctx, array, array2).map(|r| !r) } } diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index 673b9be3..41212ec0 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -46,12 +46,12 @@ mod map_functions { ctx: NativeCallContext, map: &mut Map, mut map2: Map, - ) -> Result> { + ) -> Result> { if map.len() != map2.len() { - return Ok(false.into()); + return Ok(false); } if map.is_empty() { - return Ok(true.into()); + return Ok(true); } for (m1, v1) in map.iter_mut() { @@ -61,22 +61,22 @@ mod map_functions { .map(|v| v.as_bool().unwrap_or(false))?; if !equals { - return Ok(false.into()); + return Ok(false); } } else { - return Ok(false.into()); + return Ok(false); } } - Ok(true.into()) + Ok(true) } #[rhai_fn(name = "!=", return_raw, pure)] pub fn not_equals( ctx: NativeCallContext, map: &mut Map, map2: Map, - ) -> Result> { - equals(ctx, map, map2).map(|r| (!r.as_bool().unwrap()).into()) + ) -> Result> { + equals(ctx, map, map2).map(|r| !r) } #[cfg(not(feature = "no_index"))] diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 9adb5725..86fef583 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -113,7 +113,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { #[export_module] mod int_functions { #[rhai_fn(name = "parse_int", return_raw)] - pub fn parse_int_radix(s: &str, radix: INT) -> Result> { + pub fn parse_int_radix(s: &str, radix: INT) -> Result> { if radix < 2 || radix > 36 { return EvalAltResult::ErrorArithmetic( format!("Invalid radix: '{}'", radix), @@ -122,18 +122,16 @@ mod int_functions { .into(); } - INT::from_str_radix(s.trim(), radix as u32) - .map(Into::::into) - .map_err(|err| { - EvalAltResult::ErrorArithmetic( - format!("Error parsing integer number '{}': {}", s, err), - Position::NONE, - ) - .into() - }) + INT::from_str_radix(s.trim(), radix as u32).map_err(|err| { + EvalAltResult::ErrorArithmetic( + format!("Error parsing integer number '{}': {}", s, err), + Position::NONE, + ) + .into() + }) } #[rhai_fn(name = "parse_int", return_raw)] - pub fn parse_int(s: &str) -> Result> { + pub fn parse_int(s: &str) -> Result> { parse_int_radix(s, 10) } } @@ -261,7 +259,7 @@ mod float_functions { x.is_infinite() } #[rhai_fn(name = "to_int", return_raw)] - pub fn f32_to_int(x: f32) -> Result> { + pub fn f32_to_int(x: f32) -> Result> { if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f32) { EvalAltResult::ErrorArithmetic( format!("Integer overflow: to_int({})", x), @@ -269,11 +267,11 @@ mod float_functions { ) .into() } else { - Ok((x.trunc() as INT).into()) + Ok(x.trunc() as INT) } } #[rhai_fn(name = "to_int", return_raw)] - pub fn f64_to_int(x: f64) -> Result> { + pub fn f64_to_int(x: f64) -> Result> { if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f64) { EvalAltResult::ErrorArithmetic( format!("Integer overflow: to_int({})", x), @@ -281,21 +279,18 @@ mod float_functions { ) .into() } else { - Ok((x.trunc() as INT).into()) + Ok(x.trunc() as INT) } } #[rhai_fn(return_raw)] - pub fn parse_float(s: &str) -> Result> { - s.trim() - .parse::() - .map(Into::::into) - .map_err(|err| { - EvalAltResult::ErrorArithmetic( - format!("Error parsing floating-point number '{}': {}", s, err), - Position::NONE, - ) - .into() - }) + pub fn parse_float(s: &str) -> Result> { + s.trim().parse::().map_err(|err| { + EvalAltResult::ErrorArithmetic( + format!("Error parsing floating-point number '{}': {}", s, err), + Position::NONE, + ) + .into() + }) } #[cfg(not(feature = "f32_float"))] pub mod f32_f64 { @@ -327,10 +322,10 @@ mod decimal_functions { x.round() } #[rhai_fn(name = "round", return_raw)] - pub fn round_dp(x: Decimal, dp: INT) -> Result> { + pub fn round_dp(x: Decimal, dp: INT) -> Result> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { - return Ok(x.into()); + return Ok(x); } if dp < 0 { return Err(make_err(format!( @@ -340,13 +335,13 @@ mod decimal_functions { } } - Ok(x.round_dp(dp as u32).into()) + Ok(x.round_dp(dp as u32)) } #[rhai_fn(return_raw)] - pub fn round_up(x: Decimal, dp: INT) -> Result> { + pub fn round_up(x: Decimal, dp: INT) -> Result> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { - return Ok(x.into()); + return Ok(x); } if dp < 0 { return Err(make_err(format!( @@ -356,16 +351,13 @@ mod decimal_functions { } } - Ok( - x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundUp) - .into(), - ) + Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundUp)) } #[rhai_fn(return_raw)] - pub fn round_down(x: Decimal, dp: INT) -> Result> { + pub fn round_down(x: Decimal, dp: INT) -> Result> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { - return Ok(x.into()); + return Ok(x); } if dp < 0 { return Err(make_err(format!( @@ -375,16 +367,13 @@ mod decimal_functions { } } - Ok( - x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundDown) - .into(), - ) + Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundDown)) } #[rhai_fn(return_raw)] - pub fn round_half_up(x: Decimal, dp: INT) -> Result> { + pub fn round_half_up(x: Decimal, dp: INT) -> Result> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { - return Ok(x.into()); + return Ok(x); } if dp < 0 { return Err(make_err(format!( @@ -394,16 +383,13 @@ mod decimal_functions { } } - Ok( - x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfUp) - .into(), - ) + Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfUp)) } #[rhai_fn(return_raw)] - pub fn round_half_down(x: Decimal, dp: INT) -> Result> { + pub fn round_half_down(x: Decimal, dp: INT) -> Result> { if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { - return Ok(x.into()); + return Ok(x); } if dp < 0 { return Err(make_err(format!( @@ -413,10 +399,7 @@ mod decimal_functions { } } - Ok( - x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfDown) - .into(), - ) + Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfDown)) } #[rhai_fn(name = "int", get = "int")] pub fn int(x: Decimal) -> Decimal { @@ -427,10 +410,9 @@ mod decimal_functions { x.fract() } #[rhai_fn(return_raw)] - pub fn parse_decimal(s: &str) -> Result> { + pub fn parse_decimal(s: &str) -> Result> { Decimal::from_str(s) .or_else(|_| Decimal::from_scientific(s)) - .map(Into::::into) .map_err(|err| { EvalAltResult::ErrorArithmetic( format!("Error parsing decimal number '{}': {}", s, err), diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index ce3d819e..3477c7c2 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -235,7 +235,7 @@ mod string_functions { string: &mut ImmutableString, len: INT, character: char, - ) -> Result> { + ) -> Result<(), Box> { // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { @@ -269,7 +269,7 @@ mod string_functions { } } - Ok(Dynamic::UNIT) + Ok(()) } #[rhai_fn(name = "pad", return_raw)] pub fn pad_with_string( @@ -277,7 +277,7 @@ mod string_functions { string: &mut ImmutableString, len: INT, padding: &str, - ) -> Result> { + ) -> Result<(), Box> { // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { @@ -318,7 +318,7 @@ mod string_functions { } } - Ok(Dynamic::UNIT) + Ok(()) } #[cfg(not(feature = "no_index"))] diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index f8135929..b60d4f6a 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -143,28 +143,28 @@ mod time_functions { } #[rhai_fn(return_raw, name = "+")] - pub fn add(timestamp: Instant, seconds: FLOAT) -> Result> { - add_impl(timestamp, seconds).map(Into::::into) + pub fn add(timestamp: Instant, seconds: FLOAT) -> Result> { + add_impl(timestamp, seconds) } #[rhai_fn(return_raw, name = "+=")] pub fn add_assign( timestamp: &mut Instant, seconds: FLOAT, - ) -> Result> { + ) -> Result<(), Box> { *timestamp = add_impl(*timestamp, seconds)?; - Ok(Dynamic::UNIT) + Ok(()) } #[rhai_fn(return_raw, name = "-")] - pub fn subtract(timestamp: Instant, seconds: FLOAT) -> Result> { - subtract_impl(timestamp, seconds).map(Into::::into) + pub fn subtract(timestamp: Instant, seconds: FLOAT) -> Result> { + subtract_impl(timestamp, seconds) } #[rhai_fn(return_raw, name = "-=")] pub fn subtract_assign( timestamp: &mut Instant, seconds: FLOAT, - ) -> Result> { + ) -> Result<(), Box> { *timestamp = subtract_impl(*timestamp, seconds)?; - Ok(Dynamic::UNIT) + Ok(()) } } @@ -202,28 +202,25 @@ mod time_functions { } #[rhai_fn(return_raw, name = "+")] - pub fn add(timestamp: Instant, seconds: INT) -> Result> { - add_impl(timestamp, seconds).map(Into::::into) + pub fn add(timestamp: Instant, seconds: INT) -> Result> { + add_impl(timestamp, seconds) } #[rhai_fn(return_raw, name = "+=")] - pub fn add_assign( - timestamp: &mut Instant, - seconds: INT, - ) -> Result> { + pub fn add_assign(timestamp: &mut Instant, seconds: INT) -> Result<(), Box> { *timestamp = add_impl(*timestamp, seconds)?; - Ok(Dynamic::UNIT) + Ok(()) } #[rhai_fn(return_raw, name = "-")] - pub fn subtract(timestamp: Instant, seconds: INT) -> Result> { - subtract_impl(timestamp, seconds).map(Into::::into) + pub fn subtract(timestamp: Instant, seconds: INT) -> Result> { + subtract_impl(timestamp, seconds) } #[rhai_fn(return_raw, name = "-=")] pub fn subtract_assign( timestamp: &mut Instant, seconds: INT, - ) -> Result> { + ) -> Result<(), Box> { *timestamp = subtract_impl(*timestamp, seconds)?; - Ok(Dynamic::UNIT) + Ok(()) } #[rhai_fn(name = "==")] diff --git a/src/unsafe.rs b/src/unsafe.rs index 772eb35a..de7aa1bc 100644 --- a/src/unsafe.rs +++ b/src/unsafe.rs @@ -9,7 +9,7 @@ use crate::stdlib::{ /// Cast a type into another type. #[inline(always)] -pub fn unsafe_try_cast(a: A) -> Option { +pub fn unsafe_try_cast(a: A) -> Result { if TypeId::of::() == a.type_id() { // SAFETY: Just checked we have the right type. We explicitly forget the // value immediately after moving out, removing any chance of a destructor @@ -17,10 +17,10 @@ pub fn unsafe_try_cast(a: A) -> Option { unsafe { let ret: B = ptr::read(&a as *const _ as *const B); mem::forget(a); - Some(ret) + Ok(ret) } } else { - None + Err(a) } } From 22ff68cdc920bb17d688614f594b3b47ca1a0b55 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 12:18:13 +0800 Subject: [PATCH 07/11] Fix feature builds. --- src/fn_builtin.rs | 2 +- src/packages/arithmetic.rs | 18 ++++++------------ src/packages/math_basic.rs | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/fn_builtin.rs b/src/fn_builtin.rs index 828de6fb..4b79cc62 100644 --- a/src/fn_builtin.rs +++ b/src/fn_builtin.rs @@ -130,7 +130,7 @@ pub fn get_builtin_binary_op_fn( return Some(|_, args| { let x = <$base>::from(args[0].$xx().unwrap()); let y = <$base>::from(args[1].$yy().unwrap()); - $func(x, y) + $func(x, y).map(Into::::into) }) }; } diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index 1844dc66..1346a5b3 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -445,7 +445,6 @@ pub mod decimal_functions { if cfg!(not(feature = "unchecked")) { x.checked_add(y) .ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))) - .map(Into::::into) } else { Ok(x + y) } @@ -455,7 +454,6 @@ pub mod decimal_functions { if cfg!(not(feature = "unchecked")) { x.checked_sub(y) .ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))) - .map(Into::::into) } else { Ok(x - y) } @@ -465,7 +463,6 @@ pub mod decimal_functions { if cfg!(not(feature = "unchecked")) { x.checked_mul(y) .ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))) - .map(Into::::into) } else { Ok(x * y) } @@ -479,7 +476,6 @@ pub mod decimal_functions { } else { x.checked_div(y) .ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y))) - .map(Into::::into) } } else { Ok(x / y) @@ -488,14 +484,12 @@ pub mod decimal_functions { #[rhai_fn(skip, return_raw)] pub fn modulo(x: Decimal, y: Decimal) -> Result> { if cfg!(not(feature = "unchecked")) { - x.checked_rem(y) - .ok_or_else(|| { - make_err(format!( - "Modulo division by zero or overflow: {} % {}", - x, y - )) - }) - .map(Into::::into) + x.checked_rem(y).ok_or_else(|| { + make_err(format!( + "Modulo division by zero or overflow: {} % {}", + x, y + )) + }) } else { Ok(x % y) } diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 86fef583..0047111a 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -283,7 +283,7 @@ mod float_functions { } } #[rhai_fn(return_raw)] - pub fn parse_float(s: &str) -> Result> { + pub fn parse_float(s: &str) -> Result> { s.trim().parse::().map_err(|err| { EvalAltResult::ErrorArithmetic( format!("Error parsing floating-point number '{}': {}", s, err), From 42d7736d9483f5ce536e90de9e0aa21619d3f123 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 15:16:01 +0800 Subject: [PATCH 08/11] Add conversions between Decimal and FLOAT. --- src/packages/math_basic.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 0047111a..2ed73a62 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -304,6 +304,7 @@ mod float_functions { #[cfg(feature = "decimal")] #[export_module] mod decimal_functions { + use crate::stdlib::convert::TryFrom; use rust_decimal::{ prelude::{FromStr, RoundingStrategy}, Decimal, @@ -421,6 +422,40 @@ mod decimal_functions { .into() }) } + + #[cfg(not(feature = "no_float"))] + pub mod float { + #[rhai_fn(name = "to_decimal", return_raw)] + pub fn f32_to_decimal(x: f32) -> Result> { + Decimal::try_from(x).map_err(|_| { + EvalAltResult::ErrorArithmetic( + format!("Cannot convert to Decimal: to_decimal({})", x), + Position::NONE, + ) + .into() + }) + } + #[rhai_fn(name = "to_decimal", return_raw)] + pub fn f64_to_decimal(x: f64) -> Result> { + Decimal::try_from(x).map_err(|_| { + EvalAltResult::ErrorArithmetic( + format!("Cannot convert to Decimal: to_decimal({})", x), + Position::NONE, + ) + .into() + }) + } + #[rhai_fn(return_raw)] + pub fn to_float(x: Decimal) -> Result> { + FLOAT::try_from(x).map_err(|_| { + EvalAltResult::ErrorArithmetic( + format!("Cannot convert to floating-point: to_float({})", x), + Position::NONE, + ) + .into() + }) + } + } } #[cfg(not(feature = "no_float"))] From 39fb78293ce8486d6c3c7570c2ba752023bbfbec Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 19:21:42 +0800 Subject: [PATCH 09/11] Change codegen tests for return_raw. --- codegen/Cargo.toml | 2 +- codegen/tests/test_functions.rs | 7 ++----- codegen/tests/test_modules.rs | 1 - codegen/tests/test_nested.rs | 11 +++++------ 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index e4b69a7e..1170ea08 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" proc-macro = true [dev-dependencies] -rhai = { path = "..", version = "0.19.15" } +rhai = { path = "..", version = "^0.19.15" } trybuild = "1" [dependencies] diff --git a/codegen/tests/test_functions.rs b/codegen/tests/test_functions.rs index 86def42e..9becd777 100644 --- a/codegen/tests/test_functions.rs +++ b/codegen/tests/test_functions.rs @@ -1,4 +1,3 @@ -use rhai::module_resolvers::*; use rhai::plugin::*; use rhai::{Engine, EvalAltResult, Module, FLOAT}; @@ -152,10 +151,8 @@ pub mod raw_returning_fn { y1: FLOAT, x2: FLOAT, y2: FLOAT, - ) -> Result> { - Ok(Dynamic::from( - ((y2 - y1).abs().powf(2.0) + (x2 - x1).abs().powf(2.0)).sqrt(), - )) + ) -> Result> { + Ok(((y2 - y1).abs().powf(2.0) + (x2 - x1).abs().powf(2.0)).sqrt()) } } diff --git a/codegen/tests/test_modules.rs b/codegen/tests/test_modules.rs index 0e63dad7..98764d7e 100644 --- a/codegen/tests/test_modules.rs +++ b/codegen/tests/test_modules.rs @@ -1,4 +1,3 @@ -use rhai::module_resolvers::*; use rhai::{Array, Engine, EvalAltResult, FLOAT, INT}; pub mod empty_module { diff --git a/codegen/tests/test_nested.rs b/codegen/tests/test_nested.rs index 62428282..ede543c1 100644 --- a/codegen/tests/test_nested.rs +++ b/codegen/tests/test_nested.rs @@ -1,5 +1,4 @@ -use rhai::module_resolvers::*; -use rhai::{Array, Engine, EvalAltResult, FLOAT, INT}; +use rhai::{Array, Engine, EvalAltResult, FLOAT}; pub mod one_fn_module_nested_attr { use rhai::plugin::*; @@ -10,8 +9,8 @@ pub mod one_fn_module_nested_attr { use rhai::FLOAT; #[rhai_fn(return_raw)] - pub fn get_mystic_number() -> Result> { - Ok(Dynamic::from(42.0 as FLOAT)) + pub fn get_mystic_number() -> Result> { + Ok(42.0) } } } @@ -39,8 +38,8 @@ pub mod one_fn_sub_module_nested_attr { use rhai::plugin::*; use rhai::FLOAT; #[rhai_fn(return_raw)] - pub fn get_mystic_number() -> Result> { - Ok(Dynamic::from(42.0 as FLOAT)) + pub fn get_mystic_number() -> Result> { + Ok(42.0) } } } From 7a0032fc89c9fe491122c61768f49112a9229235 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 22 Mar 2021 23:11:23 +0800 Subject: [PATCH 10/11] Move return type to param_names. --- codegen/src/function.rs | 51 +-- codegen/src/lib.rs | 4 +- codegen/src/rhai_module.rs | 3 +- codegen/src/test/function.rs | 220 +++++------- codegen/src/test/module.rs | 672 ++++++++++++++--------------------- src/plugin.rs | 7 +- 6 files changed, 391 insertions(+), 566 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index f69ed3cd..e98785e7 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -591,9 +591,8 @@ impl ExportedFn { 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 input_names_block = self.generate_input_names("Token"); + let param_names_block = self.generate_param_names("Token"); let input_types_block = self.generate_input_types("Token"); - let return_type_block = self.generate_return_type("Token"); let dyn_result_fn_block = self.generate_dynamic_fn(); let vis = self.visibility; quote! { @@ -603,10 +602,8 @@ impl ExportedFn { struct Token(); #impl_block #callable_block - #input_names_block + #param_names_block #input_types_block - #return_type_block - #[allow(unused)] #dyn_result_fn_block } } @@ -650,6 +647,8 @@ impl ExportedFn { } } else { quote_spanned! { return_span => + #[allow(unused)] + #[inline(always)] pub #dynamic_signature { Ok(Dynamic::from(#name(#(#arguments),*))) } @@ -664,21 +663,23 @@ impl ExportedFn { self.name().span(), ); quote! { + #[inline(always)] pub fn #callable_fn_name() -> CallableFunction { #token_name().into() } } } - pub fn generate_input_names(&self, on_type_name: &str) -> proc_macro2::TokenStream { + 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 input_names_fn_name: syn::Ident = syn::Ident::new( - &format!("{}_input_names", on_type_name.to_lowercase()), + let param_names_fn_name: syn::Ident = syn::Ident::new( + &format!("{}_param_names", on_type_name.to_lowercase()), self.name().span(), ); quote! { - pub fn #input_names_fn_name() -> Box<[&'static str]> { - #token_name().input_names() + #[inline(always)] + pub fn #param_names_fn_name() -> Box<[&'static str]> { + #token_name().param_names() } } } @@ -690,25 +691,13 @@ impl ExportedFn { self.name().span(), ); quote! { + #[inline(always)] pub fn #input_types_fn_name() -> Box<[TypeId]> { #token_name().input_types() } } } - pub fn generate_return_type(&self, on_type_name: &str) -> proc_macro2::TokenStream { - let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span()); - let return_type_fn_name: syn::Ident = syn::Ident::new( - &format!("{}_return_type", on_type_name.to_lowercase()), - self.name().span(), - ); - quote! { - pub fn #return_type_fn_name() -> &'static str { - #token_name().return_type() - } - } - } - pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream { let sig_name = self.name().clone(); let arg_count = self.arg_count(); @@ -885,24 +874,22 @@ impl ExportedFn { let type_name = syn::Ident::new(on_type_name, proc_macro2::Span::call_site()); quote! { 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 } - fn is_method_call(&self) -> bool { #is_method_call } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(#type_name()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec![#(#input_type_names),*].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![#(#input_type_exprs),*].into_boxed_slice() } - fn return_type(&self) -> &'static str { - #return_type - } } } } diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 7ba9e874..a8bc11e8 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -340,7 +340,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream 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_input_names().as_ref()), + Some(#gen_mod_path::token_param_names().as_ref()), #gen_mod_path::token_input_types().as_ref(), #gen_mod_path::token_callable()); }; @@ -382,7 +382,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke 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_input_names().as_ref()), + Some(#gen_mod_path::token_param_names().as_ref()), #gen_mod_path::token_input_types().as_ref(), #gen_mod_path::token_callable()); }; diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index fc4bc82a..1b83a407 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -185,9 +185,8 @@ pub fn generate_body( }); 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_input_names(&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())); - gen_fn_tokens.push(function.generate_return_type(&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 25a0886a..c0abce5b 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -277,39 +277,33 @@ mod generate_tests { use super::*; struct Token(); impl PluginFunction for Token { - fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult { + #[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())) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec![].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn() -> Result > { + #[inline(always)] pub fn dynamic_result_fn() -> Result > { Ok(Dynamic::from(do_nothing())) } } @@ -331,6 +325,7 @@ mod generate_tests { use super::*; struct Token(); 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); @@ -338,33 +333,27 @@ mod generate_tests { Ok(Dynamic::from(do_something(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn(x: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: usize) -> Result > { Ok(Dynamic::from(do_something(x))) } } @@ -386,6 +375,7 @@ mod generate_tests { use super::*; struct Token(); 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); @@ -393,33 +383,27 @@ mod generate_tests { Ok(Dynamic::from(do_something(context, arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result > { Ok(Dynamic::from(do_something(context, x))) } } @@ -444,39 +428,34 @@ mod generate_tests { use super::*; struct Token(); 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())) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec![].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "rhai::Dynamic" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn() -> Result > { + #[inline(always)] pub fn dynamic_result_fn() -> Result > { Ok(Dynamic::from(return_dynamic())) } } @@ -494,6 +473,7 @@ mod generate_tests { let expected_tokens = quote! { 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); @@ -501,18 +481,15 @@ mod generate_tests { Ok(Dynamic::from(do_something(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(TestStruct()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } }; @@ -532,6 +509,7 @@ mod generate_tests { use super::*; struct Token(); 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); @@ -540,34 +518,28 @@ mod generate_tests { Ok(Dynamic::from(add_together(arg0, arg1))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: usize", "y: usize"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "usize" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn(x: usize, y: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: usize, y: usize) -> Result > { Ok(Dynamic::from(add_together(x, y))) } } @@ -589,6 +561,7 @@ mod generate_tests { use super::*; struct Token(); 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); @@ -602,34 +575,28 @@ mod generate_tests { Ok(Dynamic::from(increment(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut usize", "y: usize"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result > { Ok(Dynamic::from(increment(x, y))) } } @@ -652,6 +619,7 @@ mod generate_tests { use super::*; struct Token(); 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); @@ -659,33 +627,27 @@ mod generate_tests { Ok(Dynamic::from(special_print(&arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { Box::new(Token()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["message: &str"].into_boxed_slice() + #[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() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn token_callable() -> CallableFunction { + #[inline(always)] pub fn token_callable() -> CallableFunction { Token().into() } - pub fn token_input_names() -> Box<[&'static str]> { - Token().input_names() + #[inline(always)] pub fn token_param_names() -> Box<[&'static str]> { + Token().param_names() } - pub fn token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn token_input_types() -> Box<[TypeId]> { Token().input_types() } - pub fn token_return_type() -> &'static str { - Token().return_type() - } #[allow(unused)] - pub fn dynamic_result_fn(message: &str) -> Result > { + #[inline(always)] pub fn dynamic_result_fn(message: &str) -> Result > { Ok(Dynamic::from(special_print(message))) } } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 90cbedc2..61645c81 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -304,39 +304,34 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_mystic_number_token(); 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())) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec![].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn get_mystic_number_token_callable() -> CallableFunction { + #[inline(always)] pub fn get_mystic_number_token_callable() -> CallableFunction { get_mystic_number_token().into() } - pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> { - get_mystic_number_token().input_names() + #[inline(always)] pub fn get_mystic_number_token_param_names() -> Box<[&'static str]> { + get_mystic_number_token().param_names() } - pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { get_mystic_number_token().input_types() } - pub fn get_mystic_number_token_return_type() -> &'static str { - get_mystic_number_token().return_type() - } } }; @@ -371,13 +366,15 @@ 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(&["x: INT", "INT"]), + &[core::any::TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct add_one_to_token(); 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); @@ -385,33 +382,27 @@ mod generate_tests { Ok(Dynamic::from(add_one_to(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_one_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } - pub fn add_one_to_token_input_names() -> Box<[&'static str]> { - add_one_to_token().input_names() + #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { + add_one_to_token().param_names() } - pub fn add_one_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } - pub fn add_one_to_token_return_type() -> &'static str { - add_one_to_token().return_type() - } } }; @@ -445,13 +436,15 @@ 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(&["x: INT", "INT"]), + &[core::any::TypeId::of::()], add_one_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct add_one_to_token(); 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); @@ -459,33 +452,27 @@ mod generate_tests { Ok(Dynamic::from(add_one_to(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_one_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } - pub fn add_one_to_token_input_names() -> Box<[&'static str]> { - add_one_to_token().input_names() + #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { + add_one_to_token().param_names() } - pub fn add_one_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } - pub fn add_one_to_token_return_type() -> &'static str { - add_one_to_token().return_type() - } } }; @@ -530,7 +517,8 @@ 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(&["x: INT", "INT"]), + &[core::any::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::()], @@ -540,6 +528,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_one_to_token(); 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); @@ -547,37 +536,32 @@ mod generate_tests { Ok(Dynamic::from(add_one_to(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_one_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_one_to_token_callable() -> CallableFunction { add_one_to_token().into() } - pub fn add_one_to_token_input_names() -> Box<[&'static str]> { - add_one_to_token().input_names() + #[inline(always)] pub fn add_one_to_token_param_names() -> Box<[&'static str]> { + add_one_to_token().param_names() } - pub fn add_one_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_one_to_token_input_types() -> Box<[TypeId]> { add_one_to_token().input_types() } - pub fn add_one_to_token_return_type() -> &'static str { - add_one_to_token().return_type() - } #[allow(non_camel_case_types)] struct add_n_to_token(); 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); @@ -586,34 +570,28 @@ mod generate_tests { Ok(Dynamic::from(add_n_to(arg0, arg1))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_n_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_n_to_token_callable() -> CallableFunction { add_n_to_token().into() } - pub fn add_n_to_token_input_names() -> Box<[&'static str]> { - add_n_to_token().input_names() + #[inline(always)] pub fn add_n_to_token_param_names() -> Box<[&'static str]> { + add_n_to_token().param_names() } - pub fn add_n_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_n_to_token_input_types() -> Box<[TypeId]> { add_n_to_token().input_types() } - pub fn add_n_to_token_return_type() -> &'static str { - add_n_to_token().return_type() - } } }; @@ -655,6 +633,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_together_token(); 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); @@ -663,34 +642,28 @@ mod generate_tests { Ok(Dynamic::from(add_together(arg0, arg1))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_together_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_together_token_callable() -> CallableFunction { add_together_token().into() } - pub fn add_together_token_input_names() -> Box<[&'static str]> { - add_together_token().input_names() + #[inline(always)] pub fn add_together_token_param_names() -> Box<[&'static str]> { + add_together_token().param_names() } - pub fn add_together_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_together_token_input_types() -> Box<[TypeId]> { add_together_token().input_types() } - pub fn add_together_token_return_type() -> &'static str { - add_together_token().return_type() - } } }; @@ -739,6 +712,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct add_together_token(); 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); @@ -747,34 +721,28 @@ mod generate_tests { Ok(Dynamic::from(add_together(arg0, arg1))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: INT", "y: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: INT", "y: INT", "INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn add_together_token_callable() -> CallableFunction { + #[inline(always)] pub fn add_together_token_callable() -> CallableFunction { add_together_token().into() } - pub fn add_together_token_input_names() -> Box<[&'static str]> { - add_together_token().input_names() + #[inline(always)] pub fn add_together_token_param_names() -> Box<[&'static str]> { + add_together_token().param_names() } - pub fn add_together_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn add_together_token_input_types() -> Box<[TypeId]> { add_together_token().input_types() } - pub fn add_together_token_return_type() -> &'static str { - add_together_token().return_type() - } } }; @@ -997,39 +965,34 @@ mod generate_tests { #[allow(non_camel_case_types)] struct get_mystic_number_token(); 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())) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec![].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["INT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "INT" - } } - pub fn get_mystic_number_token_callable() -> CallableFunction { + #[inline(always)] pub fn get_mystic_number_token_callable() -> CallableFunction { get_mystic_number_token().into() } - pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> { - get_mystic_number_token().input_names() + #[inline(always)] pub fn get_mystic_number_token_param_names() -> Box<[&'static str]> { + get_mystic_number_token().param_names() } - pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> { get_mystic_number_token().input_types() } - pub fn get_mystic_number_token_return_type() -> &'static str { - get_mystic_number_token().return_type() - } } }; @@ -1094,14 +1057,15 @@ 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(&["x: &str", "()"]), + &[core::any::TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct print_out_to_token(); 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); @@ -1109,33 +1073,27 @@ mod generate_tests { Ok(Dynamic::from(print_out_to(&arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &str"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &str", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn print_out_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn print_out_to_token_callable() -> CallableFunction { print_out_to_token().into() } - pub fn print_out_to_token_input_names() -> Box<[&'static str]> { - print_out_to_token().input_names() + #[inline(always)] pub fn print_out_to_token_param_names() -> Box<[&'static str]> { + print_out_to_token().param_names() } - pub fn print_out_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn print_out_to_token_input_types() -> Box<[TypeId]> { print_out_to_token().input_types() } - pub fn print_out_to_token_return_type() -> &'static str { - print_out_to_token().return_type() - } } }; @@ -1169,14 +1127,15 @@ 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(&["x: String", "()"]), + &[core::any::TypeId::of::()], print_out_to_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct print_out_to_token(); 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); @@ -1184,33 +1143,27 @@ mod generate_tests { Ok(Dynamic::from(print_out_to(arg0))) } - fn is_method_call(&self) -> bool { false } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: String"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: String", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn print_out_to_token_callable() -> CallableFunction { + #[inline(always)] pub fn print_out_to_token_callable() -> CallableFunction { print_out_to_token().into() } - pub fn print_out_to_token_input_names() -> Box<[&'static str]> { - print_out_to_token().input_names() + #[inline(always)] pub fn print_out_to_token_param_names() -> Box<[&'static str]> { + print_out_to_token().param_names() } - pub fn print_out_to_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn print_out_to_token_input_types() -> Box<[TypeId]> { print_out_to_token().input_types() } - pub fn print_out_to_token_return_type() -> &'static str { - print_out_to_token().return_type() - } } }; @@ -1245,14 +1198,15 @@ 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(&["x: &mut FLOAT", "y: INT", "FLOAT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct foo_token(); 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); @@ -1261,33 +1215,27 @@ mod generate_tests { Ok(Dynamic::from(foo(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT", "y: INT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT", "y: INT", "FLOAT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "FLOAT" - } } - pub fn foo_token_callable() -> CallableFunction { + #[inline(always)] pub fn foo_token_callable() -> CallableFunction { foo_token().into() } - pub fn foo_token_input_names() -> Box<[&'static str]> { - foo_token().input_names() + #[inline(always)] pub fn foo_token_param_names() -> Box<[&'static str]> { + foo_token().param_names() } - pub fn foo_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn foo_token_input_types() -> Box<[TypeId]> { foo_token().input_types() } - pub fn foo_token_return_type() -> &'static str { - foo_token().return_type() - } } }; @@ -1321,14 +1269,15 @@ 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(&["x: &mut FLOAT", "()"]), + &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct increment_token(); 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); @@ -1341,33 +1290,27 @@ mod generate_tests { Ok(Dynamic::from(increment(arg0))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn increment_token_callable() -> CallableFunction { + #[inline(always)] pub fn increment_token_callable() -> CallableFunction { increment_token().into() } - pub fn increment_token_input_names() -> Box<[&'static str]> { - increment_token().input_names() + #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { + increment_token().param_names() } - pub fn increment_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } - pub fn increment_token_return_type() -> &'static str { - increment_token().return_type() - } } }; @@ -1404,14 +1347,15 @@ 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(&["x: &mut FLOAT", "()"]), + &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct increment_token(); 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); @@ -1424,33 +1368,27 @@ mod generate_tests { Ok(Dynamic::from(increment(arg0))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn increment_token_callable() -> CallableFunction { + #[inline(always)] pub fn increment_token_callable() -> CallableFunction { increment_token().into() } - pub fn increment_token_input_names() -> Box<[&'static str]> { - increment_token().input_names() + #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { + increment_token().param_names() } - pub fn increment_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } - pub fn increment_token_return_type() -> &'static str { - increment_token().return_type() - } } #[allow(unused_imports)] use super::*; @@ -1508,14 +1446,15 @@ 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(&["x: &mut FLOAT", "()"]), + &[core::any::TypeId::of::()], increment_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct increment_token(); 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); @@ -1528,33 +1467,27 @@ mod generate_tests { Ok(Dynamic::from(increment(arg0))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut FLOAT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn increment_token_callable() -> CallableFunction { + #[inline(always)] pub fn increment_token_callable() -> CallableFunction { increment_token().into() } - pub fn increment_token_input_names() -> Box<[&'static str]> { - increment_token().input_names() + #[inline(always)] pub fn increment_token_param_names() -> Box<[&'static str]> { + increment_token().param_names() } - pub fn increment_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn increment_token_input_types() -> Box<[TypeId]> { increment_token().input_types() } - pub fn increment_token_return_type() -> &'static str { - increment_token().return_type() - } } #[allow(unused_imports)] use super::*; @@ -1619,6 +1552,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); 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); @@ -1631,33 +1565,27 @@ mod generate_tests { Ok(Dynamic::from(int_foo(arg0))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "u64"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "u64" - } } - pub fn int_foo_token_callable() -> CallableFunction { + #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } - pub fn int_foo_token_input_names() -> Box<[&'static str]> { - int_foo_token().input_names() + #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { + int_foo_token().param_names() } - pub fn int_foo_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } - pub fn int_foo_token_return_type() -> &'static str { - int_foo_token().return_type() - } } }; @@ -1692,15 +1620,18 @@ 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(&["x: &mut u64", "u64"]), + &[core::any::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(&["x: &mut u64", "u64"]), + &[core::any::TypeId::of::()], int_foo_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct int_foo_token(); 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); @@ -1713,33 +1644,27 @@ mod generate_tests { Ok(Dynamic::from(int_foo(arg0))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "u64"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "u64" - } } - pub fn int_foo_token_callable() -> CallableFunction { + #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } - pub fn int_foo_token_input_names() -> Box<[&'static str]> { - int_foo_token().input_names() + #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { + int_foo_token().param_names() } - pub fn int_foo_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } - pub fn int_foo_token_return_type() -> &'static str { - int_foo_token().return_type() - } } }; @@ -1782,6 +1707,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); 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); @@ -1795,33 +1721,27 @@ mod generate_tests { Ok(Dynamic::from(int_foo(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "y: u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "y: u64", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn int_foo_token_callable() -> CallableFunction { + #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } - pub fn int_foo_token_input_names() -> Box<[&'static str]> { - int_foo_token().input_names() + #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { + int_foo_token().param_names() } - pub fn int_foo_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } - pub fn int_foo_token_return_type() -> &'static str { - int_foo_token().return_type() - } } }; @@ -1867,6 +1787,7 @@ mod generate_tests { #[allow(non_camel_case_types)] struct int_foo_token(); 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); @@ -1880,33 +1801,27 @@ mod generate_tests { Ok(Dynamic::from(int_foo(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut u64", "y: u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut u64", "y: u64", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn int_foo_token_callable() -> CallableFunction { + #[inline(always)] pub fn int_foo_token_callable() -> CallableFunction { int_foo_token().into() } - pub fn int_foo_token_input_names() -> Box<[&'static str]> { - int_foo_token().input_names() + #[inline(always)] pub fn int_foo_token_param_names() -> Box<[&'static str]> { + int_foo_token().param_names() } - pub fn int_foo_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn int_foo_token_input_types() -> Box<[TypeId]> { int_foo_token().input_types() } - pub fn int_foo_token_return_type() -> &'static str { - int_foo_token().return_type() - } } }; @@ -1941,16 +1856,15 @@ 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(&["x: &mut MyCollection", "i: u64", "FLOAT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct get_by_index_token(); 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); @@ -1964,34 +1878,28 @@ mod generate_tests { Ok(Dynamic::from(get_by_index(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "FLOAT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "FLOAT" - } } - pub fn get_by_index_token_callable() -> CallableFunction { + #[inline(always)] pub fn get_by_index_token_callable() -> CallableFunction { get_by_index_token().into() } - pub fn get_by_index_token_input_names() -> Box<[&'static str]> { - get_by_index_token().input_names() + #[inline(always)] pub fn get_by_index_token_param_names() -> Box<[&'static str]> { + get_by_index_token().param_names() } - pub fn get_by_index_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn get_by_index_token_input_types() -> Box<[TypeId]> { get_by_index_token().input_types() } - pub fn get_by_index_token_return_type() -> &'static str { - get_by_index_token().return_type() - } } }; @@ -2026,21 +1934,18 @@ 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(&["x: &mut MyCollection", "i: u64", "FLOAT"]), + &[core::any::TypeId::of::(), core::any::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(&["x: &mut MyCollection", "i: u64", "FLOAT"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::()], get_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct get_by_index_token(); 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); @@ -2054,34 +1959,28 @@ mod generate_tests { Ok(Dynamic::from(get_by_index(arg0, arg1))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "FLOAT"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "FLOAT" - } } - pub fn get_by_index_token_callable() -> CallableFunction { + #[inline(always)] pub fn get_by_index_token_callable() -> CallableFunction { get_by_index_token().into() } - pub fn get_by_index_token_input_names() -> Box<[&'static str]> { - get_by_index_token().input_names() + #[inline(always)] pub fn get_by_index_token_param_names() -> Box<[&'static str]> { + get_by_index_token().param_names() } - pub fn get_by_index_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn get_by_index_token_input_types() -> Box<[TypeId]> { get_by_index_token().input_types() } - pub fn get_by_index_token_return_type() -> &'static str { - get_by_index_token().return_type() - } } }; @@ -2116,17 +2015,15 @@ 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(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], set_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct set_by_index_token(); 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); @@ -2141,35 +2038,29 @@ mod generate_tests { Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn set_by_index_token_callable() -> CallableFunction { + #[inline(always)] pub fn set_by_index_token_callable() -> CallableFunction { set_by_index_token().into() } - pub fn set_by_index_token_input_names() -> Box<[&'static str]> { - set_by_index_token().input_names() + #[inline(always)] pub fn set_by_index_token_param_names() -> Box<[&'static str]> { + set_by_index_token().param_names() } - pub fn set_by_index_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn set_by_index_token_input_types() -> Box<[TypeId]> { set_by_index_token().input_types() } - pub fn set_by_index_token_return_type() -> &'static str { - set_by_index_token().return_type() - } } }; @@ -2204,23 +2095,18 @@ 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(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::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(&["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]), + &[core::any::TypeId::of::(), core::any::TypeId::of::(), core::any::TypeId::of::()], set_by_index_token().into()); if flatten {} else {} } #[allow(non_camel_case_types)] struct set_by_index_token(); 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); @@ -2235,35 +2121,29 @@ mod generate_tests { Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) } - fn is_method_call(&self) -> bool { true } - fn is_variadic(&self) -> bool { false } - fn clone_boxed(&self) -> Box { + #[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()) } - fn input_names(&self) -> Box<[&'static str]> { - new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice() + #[inline(always)] fn param_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"].into_boxed_slice() } - fn input_types(&self) -> Box<[TypeId]> { + #[inline(always)] fn input_types(&self) -> Box<[TypeId]> { new_vec![TypeId::of::(), TypeId::of::(), TypeId::of::()].into_boxed_slice() } - fn return_type(&self) -> &'static str { - "()" - } } - pub fn set_by_index_token_callable() -> CallableFunction { + #[inline(always)] pub fn set_by_index_token_callable() -> CallableFunction { set_by_index_token().into() } - pub fn set_by_index_token_input_names() -> Box<[&'static str]> { - set_by_index_token().input_names() + #[inline(always)] pub fn set_by_index_token_param_names() -> Box<[&'static str]> { + set_by_index_token().param_names() } - pub fn set_by_index_token_input_types() -> Box<[TypeId]> { + #[inline(always)] pub fn set_by_index_token_input_types() -> Box<[TypeId]> { set_by_index_token().input_types() } - pub fn set_by_index_token_return_type() -> &'static str { - set_by_index_token().return_type() - } } }; diff --git a/src/plugin.rs b/src/plugin.rs index d33aab73..4a890af6 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -30,12 +30,9 @@ pub trait PluginFunction { /// 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. - fn input_names(&self) -> Box<[&'static str]>; + /// 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]>; - - /// Return a string slice of the function's return type. - fn return_type(&self) -> &'static str; } From f70225ca1dcf747e101995b54de558ddee7b2711 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 23 Mar 2021 12:13:53 +0800 Subject: [PATCH 11/11] Change HashMap to BTreeMap. --- CHANGELOG.md | 13 +++++++ Cargo.toml | 8 +--- codegen/src/rhai_module.rs | 6 +-- src/ast.rs | 21 ++--------- src/bin/rhai-repl.rs | 1 + src/dynamic.rs | 22 ++++++++++- src/engine.rs | 38 +++++++------------ src/engine_api.rs | 8 ++-- src/lib.rs | 2 +- src/module/mod.rs | 73 ++++++++++++++---------------------- src/module/resolvers/file.rs | 6 +-- src/module/resolvers/stat.rs | 4 +- src/packages/array_basic.rs | 12 +++--- src/packages/fn_basic.rs | 30 +++++++-------- src/packages/mod.rs | 2 +- src/parser.rs | 40 ++++++++++---------- src/serde/ser.rs | 4 +- src/stdlib.rs | 3 +- src/utils.rs | 60 +---------------------------- 19 files changed, 139 insertions(+), 214 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9055d3df..ad8a65cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,21 @@ 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 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. + +`HashMap` and `BTreeMap` have almost identical public API's so this change is unlikely to break a +lot of existing code. + + Breaking changes ---------------- +* `Map` is now an alias to `BTreeMap` instead of `HashMap`. This is because most object maps used have 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`. @@ -16,6 +28,7 @@ Breaking changes Enhancements ------------ +* Replaced most `HashMap` usage with `BTreeMap` for better performance when the number of items is small. * `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 c95fc996..849e2e1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ 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 -no_std = ["smallvec/union", "num-traits/libm", "hashbrown", "core-error", "libm", "ahash/compile-time-rng"] +no_std = ["smallvec/union", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] # compiling for WASM wasm-bindgen = ["instant/wasm-bindgen"] @@ -63,12 +63,6 @@ default_features = false features = ["alloc"] optional = true -[dependencies.hashbrown] -version = "0.11" -default-features = false -features = ["ahash", "nightly", "inline-more"] -optional = true - [dependencies.serde] version = "1.0" default_features = false diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 1b83a407..b1eb1947 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use quote::{quote, ToTokens}; @@ -238,8 +238,8 @@ pub fn check_rename_collisions(fns: &Vec) -> Result<(), syn::Error> }) } - let mut renames = HashMap::::new(); - let mut fn_defs = HashMap::::new(); + let mut renames = BTreeMap::::new(); + let mut fn_defs = BTreeMap::::new(); for item_fn in fns.iter() { if !item_fn.params().name.is_empty() || item_fn.params().special != FnSpecialAccess::None { diff --git a/src/ast.rs b/src/ast.rs index 5ca155a4..f420ae7a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,6 +6,7 @@ use crate::module::NamespaceRef; use crate::stdlib::{ borrow::Cow, boxed::Box, + collections::BTreeMap, fmt, hash::Hash, num::NonZeroUsize, @@ -15,7 +16,6 @@ use crate::stdlib::{ vec::Vec, }; use crate::token::Token; -use crate::utils::{HashableHashMap, StraightHasherBuilder}; use crate::{ Dynamic, FnNamespace, FnPtr, ImmutableString, Module, Position, Shared, StaticVec, INT, }; @@ -866,14 +866,7 @@ pub enum Stmt { /// `if` expr `{` stmt `}` `else` `{` stmt `}` If(Expr, Box<(StmtBlock, StmtBlock)>, Position), /// `switch` expr `{` literal or _ `=>` stmt `,` ... `}` - Switch( - Expr, - Box<( - HashableHashMap, - StmtBlock, - )>, - Position, - ), + Switch(Expr, Box<(BTreeMap, StmtBlock)>, Position), /// `while` expr `{` stmt `}` While(Expr, Box, Position), /// `do` `{` stmt `}` `while`|`until` expr @@ -1594,20 +1587,14 @@ impl Expr { #[cfg(not(feature = "no_index"))] Self::Array(x, _) if self.is_constant() => { - let mut arr = Array::with_capacity(crate::stdlib::cmp::max( - crate::engine::TYPICAL_ARRAY_SIZE, - x.len(), - )); + let mut arr = Array::with_capacity(x.len()); arr.extend(x.iter().map(|v| v.get_constant_value().unwrap())); Dynamic(Union::Array(Box::new(arr), AccessMode::ReadOnly)) } #[cfg(not(feature = "no_object"))] Self::Map(x, _) if self.is_constant() => { - let mut map = Map::with_capacity(crate::stdlib::cmp::max( - crate::engine::TYPICAL_MAP_SIZE, - x.len(), - )); + let mut map = Map::new(); map.extend( x.iter() .map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 8a03d85b..291842e2 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -61,6 +61,7 @@ fn main() { let mut engine = Engine::new(); #[cfg(not(feature = "no_module"))] + #[cfg(not(feature = "no_std"))] { // Set a file module resolver without caching let mut resolver = rhai::module_resolvers::FileModuleResolver::new(); diff --git a/src/dynamic.rs b/src/dynamic.rs index 4b52e89e..014a0ed9 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -812,8 +812,8 @@ impl Dynamic { /// A [`Vec`][Vec] does not get automatically converted to an [`Array`], but will be a generic /// restricted trait object instead, because [`Vec`][Vec] is not a supported standard type. /// - /// Similarly, passing in a [`HashMap`][std::collections::HashMap] will not get a [`Map`] - /// but a trait object. + /// Similarly, passing in a [`HashMap`][std::collections::HashMap] or + /// [`BTreeMap`][std::collections::BTreeMap] will not get a [`Map`] but a trait object. /// /// # Examples /// @@ -1696,6 +1696,7 @@ impl crate::stdlib::iter::FromIterator for Dynamic { } } #[cfg(not(feature = "no_object"))] +#[cfg(not(feature = "no_std"))] impl, T: Variant + Clone> From> for Dynamic { @@ -1712,6 +1713,23 @@ impl, T: Variant + Clone> From, T: Variant + Clone> From> + for Dynamic +{ + #[inline(always)] + fn from(value: crate::stdlib::collections::BTreeMap) -> Self { + Self(Union::Map( + Box::new( + value + .into_iter() + .map(|(k, v)| (k.into(), Dynamic::from(v))) + .collect(), + ), + AccessMode::ReadWrite, + )) + } +} impl From for Dynamic { #[inline(always)] fn from(value: FnPtr) -> Self { diff --git a/src/engine.rs b/src/engine.rs index b2a3dcfb..4d1a9541 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -14,7 +14,7 @@ use crate::stdlib::{ any::{type_name, TypeId}, borrow::Cow, boxed::Box, - collections::{HashMap, HashSet}, + collections::{BTreeMap, BTreeSet}, fmt, format, hash::{Hash, Hasher}, num::{NonZeroU8, NonZeroUsize}, @@ -23,7 +23,7 @@ use crate::stdlib::{ vec::Vec, }; use crate::syntax::CustomSyntax; -use crate::utils::{get_hasher, StraightHasherBuilder}; +use crate::utils::get_hasher; use crate::{ Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, Scope, Shared, StaticVec, @@ -32,15 +32,9 @@ use crate::{ #[cfg(not(feature = "no_index"))] use crate::{calc_fn_hash, stdlib::iter::empty, Array}; -#[cfg(not(feature = "no_index"))] -pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical - #[cfg(not(feature = "no_object"))] use crate::Map; -#[cfg(not(feature = "no_object"))] -pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical - pub type Precedence = NonZeroU8; /// _(INTERNALS)_ A stack of imported [modules][Module]. @@ -501,7 +495,7 @@ pub struct FnResolutionCacheEntry { } /// A function resolution cache. -pub type FnResolutionCache = HashMap, StraightHasherBuilder>; +pub type FnResolutionCache = BTreeMap>; /// _(INTERNALS)_ A type that holds all the current states of the [`Engine`]. /// Exported under the `internals` feature only. @@ -540,9 +534,7 @@ impl State { /// Get a mutable reference to the current function resolution cache. pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache { if self.fn_resolution_caches.0.is_empty() { - self.fn_resolution_caches - .0 - .push(HashMap::with_capacity_and_hasher(64, StraightHasherBuilder)); + self.fn_resolution_caches.0.push(BTreeMap::new()); } self.fn_resolution_caches.0.last_mut().unwrap() } @@ -711,21 +703,21 @@ pub struct Engine { /// A collection of all modules loaded into the global namespace of the Engine. pub(crate) global_modules: StaticVec>, /// A collection of all sub-modules directly loaded into the Engine. - pub(crate) global_sub_modules: HashMap>, + pub(crate) global_sub_modules: BTreeMap>, /// A module resolution service. #[cfg(not(feature = "no_module"))] pub(crate) module_resolver: Box, - /// A hashmap mapping type names to pretty-print names. - pub(crate) type_names: HashMap, + /// A map mapping type names to pretty-print names. + pub(crate) type_names: BTreeMap, - /// A hashset containing symbols to disable. - pub(crate) disabled_symbols: HashSet, - /// A hashmap containing custom keywords and precedence to recognize. - pub(crate) custom_keywords: HashMap>, + /// A set of symbols to disable. + pub(crate) disabled_symbols: BTreeSet, + /// A map containing custom keywords and precedence to recognize. + pub(crate) custom_keywords: BTreeMap>, /// Custom syntax. - pub(crate) custom_syntax: HashMap, + pub(crate) custom_syntax: BTreeMap, /// Callback closure for resolving variable access. pub(crate) resolve_var: Option, @@ -1682,8 +1674,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] Expr::Array(x, _) => { - let mut arr = - Array::with_capacity(crate::stdlib::cmp::max(TYPICAL_ARRAY_SIZE, x.len())); + let mut arr = Array::with_capacity(x.len()); for item in x.as_ref() { arr.push( self.eval_expr(scope, mods, state, lib, this_ptr, item, level)? @@ -1695,8 +1686,7 @@ impl Engine { #[cfg(not(feature = "no_object"))] Expr::Map(x, _) => { - let mut map = - Map::with_capacity(crate::stdlib::cmp::max(TYPICAL_MAP_SIZE, x.len())); + let mut map = Map::new(); for (Ident { name: key, .. }, expr) in x.as_ref() { map.insert( key.clone(), diff --git a/src/engine_api.rs b/src/engine_api.rs index 1f80b747..86c523d7 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -880,7 +880,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] pub fn register_static_module(&mut self, name: &str, module: Shared) -> &mut Self { fn register_static_module_raw( - root: &mut crate::stdlib::collections::HashMap>, + root: &mut crate::stdlib::collections::BTreeMap>, name: &str, module: Shared, ) { @@ -1012,14 +1012,14 @@ impl Engine { ast::{ASTNode, Expr, Stmt}, fn_native::shared_take_or_clone, module::resolvers::StaticModuleResolver, - stdlib::collections::HashSet, + stdlib::collections::BTreeSet, ImmutableString, }; fn collect_imports( ast: &AST, resolver: &StaticModuleResolver, - imports: &mut HashSet, + imports: &mut BTreeSet, ) { ast.walk(&mut |path| match path.last().unwrap() { // Collect all `import` statements with a string constant path @@ -1035,7 +1035,7 @@ impl Engine { let mut resolver = StaticModuleResolver::new(); let mut ast = self.compile_scripts_with_scope(scope, &[script])?; - let mut imports = HashSet::::new(); + let mut imports = Default::default(); collect_imports(&ast, &mut resolver, &mut imports); diff --git a/src/lib.rs b/src/lib.rs index 982f3e01..3a880f4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,7 +164,7 @@ pub type Array = stdlib::vec::Vec; /// /// Not available under `no_object`. #[cfg(not(feature = "no_object"))] -pub type Map = stdlib::collections::HashMap; +pub type Map = stdlib::collections::BTreeMap; #[cfg(not(feature = "no_module"))] pub use module::ModuleResolver; diff --git a/src/module/mod.rs b/src/module/mod.rs index 123c2261..13b8c405 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -7,7 +7,7 @@ use crate::fn_register::RegisterNativeFunction; use crate::stdlib::{ any::TypeId, boxed::Box, - collections::HashMap, + collections::BTreeMap, fmt, format, iter::empty, num::NonZeroUsize, @@ -16,7 +16,6 @@ use crate::stdlib::{ vec::Vec, }; use crate::token::Token; -use crate::utils::StraightHasherBuilder; use crate::{ calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString, NativeCallContext, Position, Shared, StaticVec, @@ -130,20 +129,20 @@ pub struct Module { /// ID identifying the module. id: Option, /// Sub-modules. - modules: HashMap>, + modules: BTreeMap>, /// [`Module`] variables. - variables: HashMap, + variables: BTreeMap, /// Flattened collection of all [`Module`] variables, including those in sub-modules. - all_variables: HashMap, + all_variables: BTreeMap, /// External Rust functions. - functions: HashMap, StraightHasherBuilder>, + functions: BTreeMap>, /// Flattened collection of all external Rust functions, native or scripted. /// including those in sub-modules. - all_functions: HashMap, + all_functions: BTreeMap, /// Iterator functions, keyed by the type producing the iterator. - type_iterators: HashMap, + type_iterators: BTreeMap, /// Flattened collection of iterator functions, including those in sub-modules. - all_type_iterators: HashMap, + all_type_iterators: BTreeMap, /// Is the [`Module`] indexed? indexed: bool, /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? @@ -158,8 +157,8 @@ impl Default for Module { modules: Default::default(), variables: Default::default(), all_variables: Default::default(), - functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder), - all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder), + functions: Default::default(), + all_functions: Default::default(), type_iterators: Default::default(), all_type_iterators: Default::default(), indexed: false, @@ -270,25 +269,6 @@ impl Module { Default::default() } - /// Create a new [`Module`] with a specified capacity for native Rust functions. - /// - /// # Example - /// - /// ``` - /// use rhai::Module; - /// - /// let mut module = Module::new(); - /// module.set_var("answer", 42_i64); - /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); - /// ``` - #[inline(always)] - pub fn new_with_capacity(capacity: usize) -> Self { - Self { - functions: HashMap::with_capacity_and_hasher(capacity, StraightHasherBuilder), - ..Default::default() - } - } - /// Get the ID of the [`Module`], if any. /// /// # Example @@ -520,7 +500,7 @@ impl Module { .map(|f| f.func.get_fn_def()) } - /// Get a mutable reference to the underlying [`HashMap`] of sub-modules. + /// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules. /// /// # WARNING /// @@ -528,7 +508,7 @@ impl Module { /// Thus the [`Module`] is automatically set to be non-indexed. #[cfg(not(feature = "no_module"))] #[inline(always)] - pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap> { + pub(crate) fn sub_modules_mut(&mut self) -> &mut BTreeMap> { // We must assume that the user has changed the sub-modules // (otherwise why take a mutable reference?) self.all_functions.clear(); @@ -1235,13 +1215,16 @@ impl Module { &mut self, filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool, ) -> &mut Self { - self.functions.retain(|_, f| { - if f.func.is_script() { - filter(f.namespace, f.access, f.name.as_str(), f.params) - } else { - false - } - }); + self.functions = crate::stdlib::mem::take(&mut self.functions) + .into_iter() + .filter(|(_, f)| { + if f.func.is_script() { + filter(f.namespace, f.access, f.name.as_str(), f.params) + } else { + false + } + }) + .collect(); self.all_functions.clear(); self.all_variables.clear(); @@ -1460,9 +1443,9 @@ impl Module { fn index_module<'a>( module: &'a Module, path: &mut Vec<&'a str>, - variables: &mut HashMap, - functions: &mut HashMap, - type_iterators: &mut HashMap, + variables: &mut BTreeMap, + functions: &mut BTreeMap, + type_iterators: &mut BTreeMap, ) -> bool { let mut contains_indexed_global_functions = false; @@ -1518,9 +1501,9 @@ impl Module { if !self.indexed { let mut path = Vec::with_capacity(4); - let mut variables = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); - let mut functions = HashMap::with_capacity_and_hasher(256, StraightHasherBuilder); - let mut type_iterators = HashMap::with_capacity(16); + let mut variables = Default::default(); + let mut functions = Default::default(); + let mut type_iterators = Default::default(); path.push("root"); diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index e3a86634..79ba4cf0 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -1,6 +1,6 @@ use crate::stdlib::{ boxed::Box, - collections::HashMap, + collections::BTreeMap, io::Error as IoError, path::{Path, PathBuf}, string::String, @@ -44,9 +44,9 @@ pub struct FileModuleResolver { cache_enabled: bool, #[cfg(not(feature = "sync"))] - cache: crate::stdlib::cell::RefCell>>, + cache: crate::stdlib::cell::RefCell>>, #[cfg(feature = "sync")] - cache: crate::stdlib::sync::RwLock>>, + cache: crate::stdlib::sync::RwLock>>, } impl Default for FileModuleResolver { diff --git a/src/module/resolvers/stat.rs b/src/module/resolvers/stat.rs index 4b0c0f36..89cc458f 100644 --- a/src/module/resolvers/stat.rs +++ b/src/module/resolvers/stat.rs @@ -1,4 +1,4 @@ -use crate::stdlib::{boxed::Box, collections::HashMap, ops::AddAssign, string::String}; +use crate::stdlib::{boxed::Box, collections::BTreeMap, ops::AddAssign, string::String}; use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared}; /// A static [module][Module] resolution service that serves [modules][Module] added into it. @@ -19,7 +19,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared}; /// engine.set_module_resolver(resolver); /// ``` #[derive(Debug, Clone, Default)] -pub struct StaticModuleResolver(HashMap>); +pub struct StaticModuleResolver(BTreeMap>); impl StaticModuleResolver { /// Create a new [`StaticModuleResolver`]. diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 0c4701a7..2708305a 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -1,9 +1,9 @@ #![cfg(not(feature = "no_index"))] #![allow(non_snake_case)] -use crate::engine::{OP_EQUALS, TYPICAL_ARRAY_SIZE}; +use crate::engine::OP_EQUALS; use crate::plugin::*; -use crate::stdlib::{any::TypeId, boxed::Box, cmp::max, cmp::Ordering, mem, string::ToString}; +use crate::stdlib::{any::TypeId, boxed::Box, cmp::Ordering, mem, string::ToString}; use crate::{def_package, Array, Dynamic, EvalAltResult, FnPtr, NativeCallContext, Position, INT}; def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { @@ -170,7 +170,7 @@ mod array_functions { array: &mut Array, mapper: FnPtr, ) -> Result> { - let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); + let mut ar = Array::with_capacity(array.len()); for (i, item) in array.iter().enumerate() { ar.push( @@ -203,7 +203,7 @@ mod array_functions { array: &mut Array, filter: FnPtr, ) -> Result> { - let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); + let mut ar = Array::new(); for (i, item) in array.iter().enumerate() { if filter @@ -565,7 +565,7 @@ mod array_functions { array: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); + let mut drained = Array::with_capacity(array.len()); let mut i = array.len(); @@ -625,7 +625,7 @@ mod array_functions { array: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); + let mut drained = Array::new(); let mut i = array.len(); diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index c6eab910..65ae4469 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -34,34 +34,34 @@ mod fn_ptr_functions { #[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_object"))] fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { - use crate::{ast::ScriptFnDef, stdlib::collections::HashMap, Array, Map}; + use crate::{ast::ScriptFnDef, stdlib::collections::BTreeSet, Array, Map}; // Create a metadata record for a function. fn make_metadata( - dict: &HashMap<&str, ImmutableString>, + dict: &BTreeSet, namespace: Option, f: &ScriptFnDef, ) -> Map { - let mut map = Map::with_capacity(6); + let mut map = Map::new(); if let Some(ns) = namespace { - map.insert(dict["namespace"].clone(), ns.into()); + map.insert(dict.get("namespace").unwrap().clone(), ns.into()); } - map.insert(dict["name"].clone(), f.name.clone().into()); + map.insert(dict.get("name").unwrap().clone(), f.name.clone().into()); map.insert( - dict["access"].clone(), + dict.get("access").unwrap().clone(), match f.access { - FnAccess::Public => dict["public"].clone(), - FnAccess::Private => dict["private"].clone(), + FnAccess::Public => dict.get("public").unwrap().clone(), + FnAccess::Private => dict.get("private").unwrap().clone(), } .into(), ); map.insert( - dict["is_anonymous"].clone(), + dict.get("is_anonymous").unwrap().clone(), f.name.starts_with(crate::engine::FN_ANONYMOUS).into(), ); map.insert( - dict["params"].clone(), + dict.get("params").unwrap().clone(), f.params .iter() .cloned() @@ -74,8 +74,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { } // Intern strings - let mut dict = HashMap::<&str, ImmutableString>::with_capacity(8); - [ + let dict: BTreeSet = [ "namespace", "name", "access", @@ -85,9 +84,8 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { "params", ] .iter() - .for_each(|&s| { - dict.insert(s, s.into()); - }); + .map(|&s| s.into()) + .collect(); let mut list: Array = Default::default(); @@ -100,7 +98,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { // Recursively scan modules for script-defined functions. fn scan_module( list: &mut Array, - dict: &HashMap<&str, ImmutableString>, + dict: &BTreeSet, namespace: ImmutableString, module: &Module, ) { diff --git a/src/packages/mod.rs b/src/packages/mod.rs index e54763da..7524ec3d 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -89,7 +89,7 @@ macro_rules! def_package { impl $package { pub fn new() -> Self { - let mut module = $root::Module::new_with_capacity(1024); + let mut module = $root::Module::new(); ::init(&mut module); module.build_index(); Self(module.into()) diff --git a/src/parser.rs b/src/parser.rs index 21ae4114..de7a507e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,7 +12,7 @@ use crate::optimize::OptimizationLevel; use crate::stdlib::{ borrow::Cow, boxed::Box, - collections::HashMap, + collections::BTreeMap, format, hash::{Hash, Hasher}, iter::empty, @@ -23,7 +23,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, StraightHasherBuilder}; +use crate::utils::get_hasher; use crate::{ calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position, Scope, Shared, StaticVec, AST, @@ -37,7 +37,7 @@ use crate::FnAccess; type PERR = ParseErrorType; -type FunctionsLib = HashMap, StraightHasherBuilder>; +type FunctionsLib = BTreeMap>; /// A type that encapsulates the current state of the parser. #[derive(Debug)] @@ -45,14 +45,14 @@ struct ParseState<'e> { /// Reference to the scripting [`Engine`]. engine: &'e Engine, /// Interned strings. - strings: HashMap, + interned_strings: BTreeMap, /// 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. entry_stack_len: usize, /// Tracks a list of external variables (variables that are not explicitly declared in the scope). #[cfg(not(feature = "no_closure"))] - externals: HashMap, + external_vars: BTreeMap, /// An indicator that disables variable capturing into externals one single time /// up until the nearest consumed Identifier token. /// If set to false the next call to `access_var` will not capture the variable. @@ -89,10 +89,10 @@ impl<'e> ParseState<'e> { #[cfg(not(feature = "no_function"))] max_function_expr_depth, #[cfg(not(feature = "no_closure"))] - externals: Default::default(), + external_vars: Default::default(), #[cfg(not(feature = "no_closure"))] allow_capture: true, - strings: HashMap::with_capacity(64), + interned_strings: Default::default(), stack: Vec::with_capacity(16), entry_stack_len: 0, #[cfg(not(feature = "no_module"))] @@ -130,8 +130,8 @@ impl<'e> ParseState<'e> { #[cfg(not(feature = "no_closure"))] if self.allow_capture { - if index.is_none() && !self.externals.contains_key(name) { - self.externals.insert(name.into(), _pos); + if index.is_none() && !self.external_vars.contains_key(name) { + self.external_vars.insert(name.into(), _pos); } } else { self.allow_capture = true @@ -171,12 +171,13 @@ impl<'e> ParseState<'e> { text: impl AsRef + Into, ) -> ImmutableString { #[allow(clippy::map_entry)] - if !self.strings.contains_key(text.as_ref()) { + if !self.interned_strings.contains_key(text.as_ref()) { let value = text.into(); - self.strings.insert(value.clone().into(), value.clone()); + self.interned_strings + .insert(value.clone().into(), value.clone()); value } else { - self.strings.get(text.as_ref()).unwrap().clone() + self.interned_strings.get(text.as_ref()).unwrap().clone() } } } @@ -813,7 +814,7 @@ fn parse_switch( } } - let mut table = HashMap::::new(); + let mut table = BTreeMap::::new(); let mut def_stmt = None; loop { @@ -902,13 +903,10 @@ fn parse_switch( } } - let mut final_table = HashMap::with_capacity_and_hasher(table.len(), StraightHasherBuilder); - final_table.extend(table.into_iter()); - Ok(Stmt::Switch( item, Box::new(( - final_table.into(), + table, def_stmt.unwrap_or_else(|| Stmt::Noop(Position::NONE).into()), )), settings.pos, @@ -1003,7 +1001,7 @@ fn parse_primary( let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?; #[cfg(not(feature = "no_closure"))] - new_state.externals.iter().for_each(|(closure, pos)| { + new_state.external_vars.iter().for_each(|(closure, pos)| { state.access_var(closure, *pos); }); @@ -2739,7 +2737,7 @@ fn parse_fn( #[cfg(not(feature = "no_closure"))] let externals = state - .externals + .external_vars .iter() .map(|(name, _)| name) .filter(|name| !params.contains(name)) @@ -2860,7 +2858,7 @@ fn parse_anon_fn( #[cfg(not(feature = "no_closure"))] { state - .externals + .external_vars .iter() .map(|(name, &pos)| Ident { name: name.clone(), @@ -2966,7 +2964,7 @@ impl Engine { input: &mut TokenStream, ) -> Result<(Vec, Vec>), ParseError> { let mut statements = Vec::with_capacity(16); - let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); + let mut functions = BTreeMap::new(); let mut state = ParseState::new( self, #[cfg(not(feature = "unchecked"))] diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 5f169431..6b0d221e 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -390,7 +390,7 @@ impl Serializer for &mut DynamicSerializer { #[cfg(not(feature = "no_object"))] return Ok(StructVariantSerializer { variant: _variant, - map: Map::with_capacity(_len), + map: Default::default(), }); #[cfg(feature = "no_object")] return EvalAltResult::ErrorMismatchDataType( @@ -691,7 +691,7 @@ impl serde::ser::SerializeStructVariant for StructVariantSerializer { #[cfg(not(feature = "no_object"))] fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult { - let mut map = Map::with_capacity(1); + let mut map = Map::new(); map.insert(variant.into(), value); Ok(map.into()) } diff --git a/src/stdlib.rs b/src/stdlib.rs index d1aa2f43..e0a32470 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -19,7 +19,8 @@ mod inner { pub use core_error as error; pub mod collections { - pub use hashbrown::{hash_map, hash_set, HashMap, HashSet}; + pub use alloc::collections::btree_map::BTreeMap; + pub use alloc::collections::btree_set::BTreeSet; } } diff --git a/src/utils.rs b/src/utils.rs index 3bdc9250..6be824bf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,15 +6,13 @@ use crate::stdlib::{ borrow::Borrow, boxed::Box, cmp::Ordering, - collections::HashMap, fmt, fmt::{Debug, Display}, hash::{BuildHasher, Hash, Hasher}, iter::FromIterator, - ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign}, + ops::{Add, AddAssign, Deref, Sub, SubAssign}, str::FromStr, string::{String, ToString}, - vec::Vec, }; use crate::Shared; @@ -106,62 +104,6 @@ pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 { a ^ b } -/// _(INTERNALS)_ A type that wraps a [`HashMap`] and implements [`Hash`]. -/// Exported under the `internals` feature only. -#[derive(Clone, Default)] -pub struct HashableHashMap(HashMap); - -impl From> for HashableHashMap { - #[inline(always)] - fn from(value: HashMap) -> Self { - Self(value) - } -} -impl AsRef> for HashableHashMap { - #[inline(always)] - fn as_ref(&self) -> &HashMap { - &self.0 - } -} -impl AsMut> for HashableHashMap { - #[inline(always)] - fn as_mut(&mut self) -> &mut HashMap { - &mut self.0 - } -} -impl Deref for HashableHashMap { - type Target = HashMap; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for HashableHashMap { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl Debug for HashableHashMap { - #[inline(always)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} -impl Hash for HashableHashMap { - #[inline(always)] - fn hash(&self, state: &mut B) { - let mut keys: Vec<_> = self.0.keys().collect(); - keys.sort(); - - keys.into_iter().for_each(|key| { - key.hash(state); - self.0.get(&key).unwrap().hash(state); - }); - } -} - /// The system immutable string type. /// /// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`