From 5ea08d2b506753a6eeb59350a44cbf958a867b5a Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 5 Aug 2020 17:55:36 +0800 Subject: [PATCH 01/13] Bump version. --- Cargo.toml | 2 +- RELEASES.md | 4 ++++ doc/src/context.json | 2 +- src/fn_call.rs | 10 +++++----- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6ffdea4..16066b34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai" -version = "0.18.0" +version = "0.19.0" edition = "2018" authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"] description = "Embedded scripting for Rust" diff --git a/RELEASES.md b/RELEASES.md index 23973fe7..4b6b9f6d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,10 @@ Rhai Release Notes ================== +Version 0.19.0 +============== + + Version 0.18.0 ============== diff --git a/doc/src/context.json b/doc/src/context.json index 16f803db..792990b1 100644 --- a/doc/src/context.json +++ b/doc/src/context.json @@ -1,5 +1,5 @@ { - "version": "0.18.0", + "version": "0.19.0", "repoHome": "https://github.com/jonathandturner/rhai/blob/master", "repoTree": "https://github.com/jonathandturner/rhai/tree/master", "rootUrl": "", diff --git a/src/fn_call.rs b/src/fn_call.rs index c7d9050c..a2377cee 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -694,12 +694,12 @@ impl Engine { && _fn_name == KEYWORD_IS_SHARED && idx.is_empty() { - // take call + // is_shared call Ok((target.is_shared().into(), false)) } else { #[cfg(not(feature = "no_object"))] let redirected; - let mut _hash = hash_script; + let mut hash = hash_script; // Check if it is a map method call in OOP style #[cfg(not(feature = "no_object"))] @@ -719,7 +719,7 @@ impl Engine { .for_each(|(i, v)| idx.insert(i, v)); } // Recalculate the hash based on the new function name and new arguments - _hash = if native { + hash = if native { 0 } else { calc_fn_hash(empty(), _fn_name, idx.len(), empty()) @@ -729,7 +729,7 @@ impl Engine { }; if native { - _hash = 0; + hash = 0; } // Attached object pointer in front of the arguments @@ -737,7 +737,7 @@ impl Engine { let args = arg_values.as_mut(); self.exec_fn_call( - state, lib, _fn_name, _hash, args, is_ref, true, pub_only, None, def_val, level, + state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, level, ) }?; From ae11dbbefe003ff614ef6aef7049b9f15c9ce8e6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 5 Aug 2020 22:53:01 +0800 Subject: [PATCH 02/13] Fix feature flags. --- .github/workflows/build.yml | 1 - Cargo.toml | 3 +-- RELEASES.md | 6 +----- doc/src/context.json | 2 +- src/any.rs | 4 ++-- src/api.rs | 15 +++++++++++---- src/fn_call.rs | 13 ++++++++----- src/fn_native.rs | 35 ++++++++++++++++++++++------------- src/module.rs | 6 ++---- src/optimize.rs | 7 +++---- src/parser.rs | 7 +++---- src/settings.rs | 4 +++- src/token.rs | 2 ++ tests/closures.rs | 1 + 14 files changed, 60 insertions(+), 46 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db8a63d9..ee08bdeb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,6 @@ on: push: branches: - master - - closures pull_request: {} jobs: diff --git a/Cargo.toml b/Cargo.toml index 16066b34..ea523cb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai" -version = "0.19.0" +version = "0.18.1" edition = "2018" authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"] description = "Embedded scripting for Rust" @@ -23,7 +23,6 @@ smallvec = { version = "1.4.1", default-features = false } [features] #default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"] default = [] -plugins = [] # custom plugins support unchecked = [] # unchecked arithmetic sync = [] # restrict to only types that implement Send + Sync no_optimize = [] # no script optimizer diff --git a/RELEASES.md b/RELEASES.md index 4b6b9f6d..fc8f6d28 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,11 +1,7 @@ Rhai Release Notes ================== -Version 0.19.0 -============== - - -Version 0.18.0 +Version 0.18.1 ============== This version adds: diff --git a/doc/src/context.json b/doc/src/context.json index 792990b1..fb6e4afd 100644 --- a/doc/src/context.json +++ b/doc/src/context.json @@ -1,5 +1,5 @@ { - "version": "0.19.0", + "version": "0.18.1", "repoHome": "https://github.com/jonathandturner/rhai/blob/master", "repoTree": "https://github.com/jonathandturner/rhai/tree/master", "rootUrl": "", diff --git a/src/any.rs b/src/any.rs index aa218127..318b97d1 100644 --- a/src/any.rs +++ b/src/any.rs @@ -410,7 +410,7 @@ impl fmt::Display for Dynamic { } #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell) => fmt::Display::fmt(*cell.read_lock().unwrap(), f), + Union::Shared(cell) => fmt::Display::fmt(&*cell.read().unwrap(), f), } } } @@ -448,7 +448,7 @@ impl fmt::Debug for Dynamic { } #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell) => fmt::Display::fmt(*cell.read_lock().unwrap(), f), + Union::Shared(cell) => fmt::Debug::fmt(&*cell.read().unwrap(), f), } } } diff --git a/src/api.rs b/src/api.rs index 43aaf6d5..cdb4a801 100644 --- a/src/api.rs +++ b/src/api.rs @@ -3,10 +3,9 @@ use crate::any::{Dynamic, Variant}; use crate::engine::{Engine, Imports, State}; use crate::error::ParseError; -use crate::fn_call::ensure_no_data_race; use crate::fn_native::{IteratorFn, SendSync}; use crate::module::{FuncReturn, Module}; -use crate::optimize::{optimize_into_ast, OptimizationLevel}; +use crate::optimize::OptimizationLevel; use crate::parser::AST; use crate::result::EvalAltResult; use crate::scope::Scope; @@ -24,14 +23,22 @@ use crate::{ }; #[cfg(not(feature = "no_function"))] -use crate::{engine::get_script_function_by_signature, fn_args::FuncArgs, utils::StaticVec}; +use crate::{ + engine::get_script_function_by_signature, fn_args::FuncArgs, fn_call::ensure_no_data_race, + utils::StaticVec, +}; + +#[cfg(not(feature = "no_optimize"))] +use crate::optimize::optimize_into_ast; use crate::stdlib::{ any::{type_name, TypeId}, boxed::Box, - mem, }; +#[cfg(not(feature = "no_optimize"))] +use crate::stdlib::mem; + #[cfg(not(feature = "no_std"))] #[cfg(not(target_arch = "wasm32"))] use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; diff --git a/src/fn_call.rs b/src/fn_call.rs index a2377cee..d93ba533 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -34,6 +34,7 @@ use crate::engine::{FN_IDX_GET, FN_IDX_SET}; use crate::engine::{Map, Target, FN_GET, FN_SET}; #[cfg(not(feature = "no_closure"))] +#[cfg(not(feature = "no_function"))] use crate::scope::Entry as ScopeEntry; use crate::stdlib::{ @@ -48,6 +49,7 @@ use crate::stdlib::{ }; #[cfg(not(feature = "no_closure"))] +#[cfg(not(feature = "no_function"))] use crate::stdlib::{collections::HashSet, string::String}; /// Extract the property name from a getter function name. @@ -140,6 +142,7 @@ impl Drop for ArgBackup<'_> { // Add captured variables into scope #[cfg(not(feature = "no_closure"))] +#[cfg(not(feature = "no_function"))] fn add_captured_variables_into_scope<'s>( externals: &HashSet, captured: Scope<'s>, @@ -449,11 +452,11 @@ impl Engine { hash_script: u64, args: &mut FnCallArgs, is_ref: bool, - is_method: bool, + _is_method: bool, pub_only: bool, _capture: Option, def_val: Option, - level: usize, + _level: usize, ) -> Result<(Dynamic, bool), Box> { // Check for data race. if cfg!(not(feature = "no_closure")) { @@ -510,7 +513,7 @@ impl Engine { add_captured_variables_into_scope(&func.externals, captured, scope); } - let result = if is_method { + let result = if _is_method { // Method call of script function - map first argument to `this` let (first, rest) = args.split_at_mut(1); self.call_script_fn( @@ -522,7 +525,7 @@ impl Engine { fn_name, func, rest, - level, + _level, )? } else { // Normal call of script function - map first argument to `this` @@ -531,7 +534,7 @@ impl Engine { backup.change_first_arg_to_copy(is_ref, args); let result = self.call_script_fn( - scope, mods, state, lib, &mut None, fn_name, func, args, level, + scope, mods, state, lib, &mut None, fn_name, func, args, _level, ); // Restore the original reference diff --git a/src/fn_native.rs b/src/fn_native.rs index a972793b..149e720e 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,21 +1,20 @@ //! Module defining interfaces to native-Rust functions. use crate::any::Dynamic; -use crate::calc_fn_hash; use crate::engine::Engine; use crate::module::Module; -use crate::parser::FnAccess; +use crate::parser::{FnAccess, ScriptFnDef}; use crate::result::EvalAltResult; use crate::token::{is_valid_identifier, Position}; use crate::utils::ImmutableString; #[cfg(not(feature = "no_function"))] -use crate::{module::FuncReturn, parser::ScriptFnDef, utils::StaticVec}; +use crate::{calc_fn_hash, module::FuncReturn, utils::StaticVec}; -use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, iter::empty, string::String, vec::Vec}; +use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, string::String, vec::Vec}; #[cfg(not(feature = "no_function"))] -use crate::stdlib::mem; +use crate::stdlib::{iter::empty, mem}; #[cfg(not(feature = "sync"))] use crate::stdlib::rc::Rc; @@ -293,10 +292,11 @@ impl CallableFunction { } } /// Is this a Rhai-scripted function? - #[cfg(not(feature = "no_function"))] pub fn is_script(&self) -> bool { match self { + #[cfg(not(feature = "no_function"))] Self::Script(_) => true, + Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false, } } @@ -314,6 +314,8 @@ impl CallableFunction { pub fn access(&self) -> FnAccess { match self { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => FnAccess::Public, + + #[cfg(not(feature = "no_function"))] Self::Script(f) => f.access, } } @@ -348,10 +350,11 @@ impl CallableFunction { /// # Panics /// /// Panics if the `CallableFunction` is not `Script`. - #[cfg(not(feature = "no_function"))] pub fn get_fn_def(&self) -> &ScriptFnDef { match self { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(), + + #[cfg(not(feature = "no_function"))] Self::Script(f) => f, } } @@ -385,16 +388,22 @@ impl From for CallableFunction { } } -#[cfg(not(feature = "no_function"))] impl From for CallableFunction { - fn from(func: ScriptFnDef) -> Self { - Self::Script(func.into()) + fn from(_func: ScriptFnDef) -> Self { + #[cfg(feature = "no_function")] + unreachable!(); + + #[cfg(not(feature = "no_function"))] + Self::Script(_func.into()) } } -#[cfg(not(feature = "no_function"))] impl From> for CallableFunction { - fn from(func: Shared) -> Self { - Self::Script(func) + fn from(_func: Shared) -> Self { + #[cfg(feature = "no_function")] + unreachable!(); + + #[cfg(not(feature = "no_function"))] + Self::Script(_func) } } diff --git a/src/module.rs b/src/module.rs index fa23abd6..57fe8eb5 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,13 +4,13 @@ use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; use crate::engine::Engine; use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync}; -use crate::parser::{FnAccess, FnAccess::Public}; +use crate::parser::{FnAccess, FnAccess::Public, ScriptFnDef}; use crate::result::EvalAltResult; use crate::token::{Position, Token}; use crate::utils::{StaticVec, StraightHasherBuilder}; #[cfg(not(feature = "no_function"))] -use crate::{fn_native::Shared, parser::ScriptFnDef}; +use crate::fn_native::Shared; #[cfg(not(feature = "no_module"))] use crate::{ @@ -258,7 +258,6 @@ impl Module { /// Set a script-defined function into the module. /// /// If there is an existing function of the same name and number of arguments, it is replaced. - #[cfg(not(feature = "no_function"))] pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) -> &mut Self { // None + function name + number of arguments. let hash_script = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty()); @@ -1003,7 +1002,6 @@ impl Module { } /// Get an iterator to the functions in the module. - #[cfg(not(feature = "no_function"))] pub(crate) fn iter_fn( &self, ) -> impl Iterator, Func)> { diff --git a/src/optimize.rs b/src/optimize.rs index 7503c592..ab4147c3 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -7,13 +7,10 @@ use crate::engine::{ }; use crate::fn_native::FnPtr; use crate::module::Module; -use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST}; +use crate::parser::{map_dynamic_to_expr, Expr, ReturnType, ScriptFnDef, Stmt, AST}; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; use crate::utils::StaticVec; -#[cfg(not(feature = "no_function"))] -use crate::parser::ReturnType; - #[cfg(feature = "internals")] use crate::parser::CustomExpr; @@ -46,10 +43,12 @@ impl OptimizationLevel { self == Self::None } /// Is the `OptimizationLevel` Simple. + #[cfg(not(feature = "no_optimize"))] pub fn is_simple(self) -> bool { self == Self::Simple } /// Is the `OptimizationLevel` Full. + #[cfg(not(feature = "no_optimize"))] pub fn is_full(self) -> bool { self == Self::Full } diff --git a/src/parser.rs b/src/parser.rs index 272215ac..c66fa56b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,9 +2,7 @@ use crate::any::{Dynamic, Union}; use crate::calc_fn_hash; -use crate::engine::{ - Engine, KEYWORD_FN_PTR_CURRY, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT, -}; +use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; use crate::error::{LexError, ParseError, ParseErrorType}; use crate::fn_native::{FnPtr, Shared}; use crate::module::{Module, ModuleRef}; @@ -15,7 +13,7 @@ use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, To use crate::utils::{StaticVec, StraightHasherBuilder}; #[cfg(not(feature = "no_function"))] -use crate::engine::FN_ANONYMOUS; +use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY}; #[cfg(not(feature = "no_object"))] use crate::engine::{make_getter, make_setter}; @@ -3135,6 +3133,7 @@ fn parse_fn( } /// Creates a curried expression from a list of external variables +#[cfg(not(feature = "no_function"))] fn make_curry_from_externals( fn_expr: Expr, externals: StaticVec<(String, Position)>, diff --git a/src/settings.rs b/src/settings.rs index d4949a41..6e9e020d 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,13 +1,15 @@ //! Configuration settings for `Engine`. use crate::engine::Engine; -use crate::optimize::OptimizationLevel; use crate::packages::PackageLibrary; use crate::token::{is_valid_identifier, Token}; #[cfg(not(feature = "no_module"))] use crate::module::ModuleResolver; +#[cfg(not(feature = "no_optimize"))] +use crate::optimize::OptimizationLevel; + use crate::stdlib::{format, string::String}; #[cfg(not(feature = "no_module"))] diff --git a/src/token.rs b/src/token.rs index 4a4d5fc1..c1968d23 100644 --- a/src/token.rs +++ b/src/token.rs @@ -680,6 +680,7 @@ impl Token { } /// Convert a token into a function name, if possible. + #[cfg(not(feature = "no_function"))] pub(crate) fn into_function_name_for_override(self) -> Result { match self { Self::Reserved(s) if can_override_keyword(&s) => Ok(s), @@ -1442,6 +1443,7 @@ pub fn is_keyword_function(name: &str) -> bool { } /// Can this keyword be overridden as a function? +#[cfg(not(feature = "no_function"))] #[inline(always)] pub fn can_override_keyword(name: &str) -> bool { match name { diff --git a/tests/closures.rs b/tests/closures.rs index 0736654b..3fc1cbd5 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -83,6 +83,7 @@ fn test_closures() -> Result<(), Box> { #[test] #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_object"))] +#[cfg(not(feature = "sync"))] fn test_closures_data_race() -> Result<(), Box> { let engine = Engine::new(); From bb2c9f7c5933bff181ea21f28c4fc91578c58434 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 5 Aug 2020 23:11:54 +0800 Subject: [PATCH 03/13] Bump version. --- Cargo.toml | 2 +- RELEASES.md | 6 +++++- doc/src/context.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ea523cb9..73cc5b2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai" -version = "0.18.1" +version = "0.19.0" edition = "2018" authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"] description = "Embedded scripting for Rust" diff --git a/RELEASES.md b/RELEASES.md index fc8f6d28..87cb5bdb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,10 @@ Rhai Release Notes ================== +Version 0.19.0 +============== + + Version 0.18.1 ============== @@ -8,7 +12,7 @@ This version adds: * Anonymous functions (in Rust closure syntax). Simplifies creation of single-use ad-hoc functions. * Currying of function pointers. -* Closures - auto-currying of anonymous functions to capture shared variables from the external scope. +* Closures - auto-currying of anonymous functions to capture shared variables from the external scope. Use the `no_closure` feature to disable sharing values and capturing. * Binding the `this` pointer in a function pointer `call`. * Capturing call scope via `func!(...)` syntax. diff --git a/doc/src/context.json b/doc/src/context.json index fb6e4afd..792990b1 100644 --- a/doc/src/context.json +++ b/doc/src/context.json @@ -1,5 +1,5 @@ { - "version": "0.18.1", + "version": "0.19.0", "repoHome": "https://github.com/jonathandturner/rhai/blob/master", "repoTree": "https://github.com/jonathandturner/rhai/tree/master", "rootUrl": "", From ffe52bf437c8f9a658a99d0acf20de2545afa5cc Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 5 Aug 2020 23:23:53 +0800 Subject: [PATCH 04/13] Allow omitting the alias in import statement. --- doc/src/language/modules/import.md | 11 +++++++++-- src/engine.rs | 9 ++++++--- src/parser.rs | 14 ++++---------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/doc/src/language/modules/import.md b/doc/src/language/modules/import.md index 5e0a377a..b592ff74 100644 --- a/doc/src/language/modules/import.md +++ b/doc/src/language/modules/import.md @@ -7,10 +7,17 @@ Import a Module `import` Statement ----------------- -A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++. +A module can be _imported_ via the `import` statement, and be given a name. +Its members can be accessed via '`::`' similar to C++. + +A module that is only `import`-ed but not under any module name is commonly used for initialization purposes, +where the module script contains initialization statements that puts the functions registered with the +[`Engine`] into a particular state. ```rust -import "crypto" as lock; // import the script file 'crypto.rhai' as a module named 'lock' +import "crypto_init"; // run the script file 'crypto_init.rhai' without creating an imported module + +import "crypto" as lock; // run the script file 'crypto.rhai' and import it as a module named 'lock' lock::encrypt(secret); // use functions defined under the module via '::' diff --git a/src/engine.rs b/src/engine.rs index 65228a8f..d485f22b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1806,7 +1806,7 @@ impl Engine { // Import statement #[cfg(not(feature = "no_module"))] Stmt::Import(x) => { - let (expr, (name, _pos), _) = x.as_ref(); + let (expr, alias, _pos) = x.as_ref(); // Guard against too many modules #[cfg(not(feature = "unchecked"))] @@ -1820,8 +1820,11 @@ impl Engine { { if let Some(resolver) = &self.module_resolver { let mut module = resolver.resolve(self, &path, expr.position())?; - module.index_all_sub_modules(); - mods.push((name.clone().into(), module)); + + if let Some((name, _)) = alias { + module.index_all_sub_modules(); + mods.push((name.clone().into(), module)); + } state.modules += 1; diff --git a/src/parser.rs b/src/parser.rs index c66fa56b..8b3bf3ea 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -568,7 +568,7 @@ pub enum Stmt { ReturnWithVal(Box<((ReturnType, Position), Option, Position)>), /// import expr as module #[cfg(not(feature = "no_module"))] - Import(Box<(Expr, (String, Position), Position)>), + Import(Box<(Expr, Option<(String, Position)>, Position)>), /// expr id as name, ... #[cfg(not(feature = "no_module"))] Export( @@ -2685,14 +2685,8 @@ fn parse_import( let expr = parse_expr(input, state, lib, settings.level_up())?; // import expr as ... - match input.next().unwrap() { - (Token::As, _) => (), - (_, pos) => { - return Err( - PERR::MissingToken(Token::As.into(), "in this import statement".into()) - .into_err(pos), - ) - } + if !match_token(input, Token::As)? { + return Ok(Stmt::Import(Box::new((expr, None, token_pos)))); } // import expr as name ... @@ -2709,7 +2703,7 @@ fn parse_import( Ok(Stmt::Import(Box::new(( expr, - (name, settings.pos), + Some((name, settings.pos)), token_pos, )))) } From fff08d29b6e6e8ee6fa020157e61699b1e889d65 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 00:01:16 +0800 Subject: [PATCH 05/13] Fix CI. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee08bdeb..f4a476a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --all {{matrix.flags}} + args: --all ${{matrix.flags}} # no-std builds are a bit more extensive to test no_std_build: name: NoStdBuild From 41b41ff834e114778689207aac9224a014eca91c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 00:24:25 +0800 Subject: [PATCH 06/13] Fix tests. --- tests/side_effects.rs | 8 ++++---- tests/stack.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/side_effects.rs b/tests/side_effects.rs index bee1cb2f..69e33de1 100644 --- a/tests/side_effects.rs +++ b/tests/side_effects.rs @@ -5,16 +5,16 @@ use std::sync::{Arc, Mutex, RwLock}; /// Simulate a command object. struct Command { /// Simulate an external state. - state: i64, + state: INT, } impl Command { /// Do some action. - pub fn action(&mut self, val: i64) { + pub fn action(&mut self, val: INT) { self.state = val; } /// Get current value. - pub fn get(&self) -> i64 { + pub fn get(&self) -> INT { self.state } } @@ -39,7 +39,7 @@ fn test_side_effects_command() -> Result<(), Box> { // Register type. engine.register_type_with_name::("CommandType"); - engine.register_fn("action", |api: &mut API, x: i64| { + engine.register_fn("action", |api: &mut API, x: INT| { let mut command = api.lock().unwrap(); let val = command.get(); command.action(val + x); diff --git a/tests/stack.rs b/tests/stack.rs index 29828fef..47202b47 100644 --- a/tests/stack.rs +++ b/tests/stack.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "unchecked"))] -use rhai::{Engine, EvalAltResult, ParseError, ParseErrorType}; +use rhai::{Engine, EvalAltResult, ParseError, ParseErrorType, INT}; #[test] #[cfg(not(feature = "no_function"))] @@ -7,7 +7,7 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box> { let engine = Engine::new(); assert_eq!( - engine.eval::( + engine.eval::( r" fn foo(n) { if n <= 1 { 0 } else { n + foo(n-1) } } foo(8) From 2f395492de5a9ce4c253ec227cdfc02f7ad83108 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 10:17:32 +0800 Subject: [PATCH 07/13] Simply error code. --- doc/src/engine/custom-syntax.md | 6 +- doc/src/rust/modules/imp-resolver.md | 2 +- src/api.rs | 31 ++---- src/engine.rs | 148 +++++++++++---------------- src/fn_call.rs | 80 ++++++++------- src/fn_native.rs | 5 +- src/module.rs | 12 +-- src/packages/arithmetic.rs | 93 +++++++++-------- src/packages/array_basic.rs | 5 +- src/packages/math_basic.rs | 10 +- src/packages/string_more.rs | 8 +- src/packages/time_basic.rs | 12 +-- src/result.rs | 6 ++ src/serde/de.rs | 10 +- src/serde/ser.rs | 38 +++---- src/serde/str.rs | 5 +- 16 files changed, 228 insertions(+), 243 deletions(-) diff --git a/doc/src/engine/custom-syntax.md b/doc/src/engine/custom-syntax.md index 8f308106..8d0820c8 100644 --- a/doc/src/engine/custom-syntax.md +++ b/doc/src/engine/custom-syntax.md @@ -200,8 +200,10 @@ fn implementation_func( // Evaluate the condition expression let stop = !engine.eval_expression_tree(context, scope, condition)? - .as_bool().map_err(|_| EvalAltResult::ErrorBooleanArgMismatch( - "do-while".into(), expr.position()))?; + .as_bool() + .map_err(|_| EvalAltResult::ErrorBooleanArgMismatch( + "do-while".into(), expr.position() + ))?; if stop { break; diff --git a/doc/src/rust/modules/imp-resolver.md b/doc/src/rust/modules/imp-resolver.md index 55d68315..d1d9ed38 100644 --- a/doc/src/rust/modules/imp-resolver.md +++ b/doc/src/rust/modules/imp-resolver.md @@ -38,7 +38,7 @@ impl ModuleResolver for MyModuleResolver { let module: Module = load_secret_module(path); Ok(module) } else { - Err(Box::new(EvalAltResult::ErrorModuleNotFound(path.into(), pos))) + Err(EvalAltResult::ErrorModuleNotFound(path.into(), pos).into()) } } } diff --git a/src/api.rs b/src/api.rs index cdb4a801..34af07a1 100644 --- a/src/api.rs +++ b/src/api.rs @@ -608,21 +608,13 @@ impl Engine { #[cfg(not(target_arch = "wasm32"))] fn read_file(path: PathBuf) -> Result> { let mut f = File::open(path.clone()).map_err(|err| { - Box::new(EvalAltResult::ErrorReadingScriptFile( - path.clone(), - Position::none(), - err, - )) + EvalAltResult::ErrorReadingScriptFile(path.clone(), Position::none(), err) })?; let mut contents = String::new(); f.read_to_string(&mut contents).map_err(|err| { - Box::new(EvalAltResult::ErrorReadingScriptFile( - path.clone(), - Position::none(), - err, - )) + EvalAltResult::ErrorReadingScriptFile(path.clone(), Position::none(), err) })?; Ok(contents) @@ -1042,11 +1034,12 @@ impl Engine { let typ = self.map_type_name(result.type_name()); return result.try_cast::().ok_or_else(|| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), typ.into(), Position::none(), - )) + ) + .into() }); } @@ -1190,11 +1183,12 @@ impl Engine { let typ = self.map_type_name(result.type_name()); return result.try_cast().ok_or_else(|| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), typ.into(), Position::none(), - )) + ) + .into() }); } @@ -1278,13 +1272,8 @@ impl Engine { ) -> FuncReturn { let lib = lib.as_ref(); let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - let fn_def = - get_script_function_by_signature(lib, name, args.len(), true).ok_or_else(|| { - Box::new(EvalAltResult::ErrorFunctionNotFound( - name.into(), - Position::none(), - )) - })?; + let fn_def = get_script_function_by_signature(lib, name, args.len(), true) + .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?; let mut state = State::new(); let mut mods = Imports::new(); diff --git a/src/engine.rs b/src/engine.rs index d485f22b..9a771ac6 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -228,9 +228,7 @@ impl Target<'_> { #[cfg(not(feature = "no_object"))] Self::LockGuard((r, _)) => **r = new_val, Self::Value(_) => { - return Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS( - Position::none(), - ))) + return EvalAltResult::ErrorAssignmentToUnknownLHS(Position::none()).into(); } #[cfg(not(feature = "no_index"))] Self::StringChar(string, index, _) if string.is::() => { @@ -517,12 +515,7 @@ pub fn search_imports<'s>( .rev() .find(|(n, _)| n == root) .map(|(_, m)| m) - .ok_or_else(|| { - Box::new(EvalAltResult::ErrorModuleNotFound( - root.to_string(), - *root_pos, - )) - })? + .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *root_pos))? }) } @@ -550,12 +543,7 @@ pub fn search_imports_mut<'s>( .rev() .find(|(n, _)| n == root) .map(|(_, m)| m) - .ok_or_else(|| { - Box::new(EvalAltResult::ErrorModuleNotFound( - root.to_string(), - *root_pos, - )) - })? + .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *root_pos))? }) } @@ -577,10 +565,11 @@ pub fn search_namespace<'s, 'a>( .get_qualified_var_mut(*hash_var) .map_err(|err| match *err { EvalAltResult::ErrorVariableNotFound(_, _) => { - Box::new(EvalAltResult::ErrorVariableNotFound( + EvalAltResult::ErrorVariableNotFound( format!("{}{}", modules, name), *pos, - )) + ) + .into() } _ => err.new_position(*pos), })?; @@ -612,7 +601,7 @@ pub fn search_scope_only<'s, 'a>( if let Some(val) = this_ptr { return Ok(((*val).into(), KEYWORD_THIS, ScopeEntryType::Normal, *pos)); } else { - return Err(Box::new(EvalAltResult::ErrorUnboundThis(*pos))); + return EvalAltResult::ErrorUnboundThis(*pos).into(); } } @@ -625,7 +614,7 @@ pub fn search_scope_only<'s, 'a>( // Find the variable in the scope scope .get_index(name) - .ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.into(), *pos)))? + .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.into(), *pos))? .0 }; @@ -634,7 +623,7 @@ pub fn search_scope_only<'s, 'a>( // 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 Err(Box::new(EvalAltResult::ErrorDataRace(name.into(), *pos))); + // return EvalAltResult::ErrorDataRace(name.into(), *pos).into(); // } Ok((val, name, typ, *pos)) @@ -966,10 +955,7 @@ impl Engine { } } // Syntax error - _ => Err(Box::new(EvalAltResult::ErrorDotExpr( - "".into(), - rhs.position(), - ))), + _ => EvalAltResult::ErrorDotExpr("".into(), rhs.position()).into(), } } @@ -1016,10 +1002,8 @@ impl Engine { // Constants cannot be modified match typ { ScopeEntryType::Constant if new_val.is_some() => { - return Err(Box::new(EvalAltResult::ErrorAssignmentToConstant( - var_name.to_string(), - pos, - ))); + return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos) + .into(); } ScopeEntryType::Constant | ScopeEntryType::Normal => (), } @@ -1033,9 +1017,7 @@ impl Engine { } // {expr}.??? = ??? or {expr}[???] = ??? expr if new_val.is_some() => { - return Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS( - expr.position(), - ))); + return EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(); } // {expr}.??? or {expr}[???] expr => { @@ -1160,12 +1142,10 @@ impl Engine { arr.get_mut(index as usize) .map(Target::from) .ok_or_else(|| { - Box::new(EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos)) + EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into() }) } else { - Err(Box::new(EvalAltResult::ErrorArrayBounds( - arr_len, index, idx_pos, - ))) + EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into() } } @@ -1200,13 +1180,11 @@ impl Engine { if index >= 0 { let offset = index as usize; let ch = s.chars().nth(offset).ok_or_else(|| { - Box::new(EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos)) + EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos) })?; Ok(Target::StringChar(val, offset, ch.into())) } else { - Err(Box::new(EvalAltResult::ErrorStringBounds( - chars_len, index, idx_pos, - ))) + EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos).into() } } @@ -1227,10 +1205,11 @@ impl Engine { }) } - _ => Err(Box::new(EvalAltResult::ErrorIndexingType( + _ => EvalAltResult::ErrorIndexingType( self.map_type_name(val.type_name()).into(), Position::none(), - ))), + ) + .into(), } } @@ -1284,15 +1263,15 @@ impl Engine { // Only allows String or char Dynamic(Union::Str(s)) => Ok(rhs_value.contains_key(&s).into()), Dynamic(Union::Char(c)) => Ok(rhs_value.contains_key(&c.to_string()).into()), - _ => Err(Box::new(EvalAltResult::ErrorInExpr(lhs.position()))), + _ => EvalAltResult::ErrorInExpr(lhs.position()).into(), }, Dynamic(Union::Str(rhs_value)) => match lhs_value { // Only allows String or char Dynamic(Union::Str(s)) => Ok(rhs_value.contains(s.as_str()).into()), Dynamic(Union::Char(c)) => Ok(rhs_value.contains(c).into()), - _ => Err(Box::new(EvalAltResult::ErrorInExpr(lhs.position()))), + _ => EvalAltResult::ErrorInExpr(lhs.position()).into(), }, - _ => Err(Box::new(EvalAltResult::ErrorInExpr(rhs.position()))), + _ => EvalAltResult::ErrorInExpr(rhs.position()).into(), } } @@ -1323,7 +1302,7 @@ impl Engine { if let Some(val) = this_ptr { Ok(val.clone()) } else { - Err(Box::new(EvalAltResult::ErrorUnboundThis((x.0).1))) + EvalAltResult::ErrorUnboundThis((x.0).1).into() } } Expr::Variable(_) => { @@ -1454,16 +1433,13 @@ impl Engine { Ok(Default::default()) } // Error assignment to constant - expr if expr.is_constant() => { - Err(Box::new(EvalAltResult::ErrorAssignmentToConstant( - expr.get_constant_str(), - expr.position(), - ))) - } - // Syntax error - expr => Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS( + expr if expr.is_constant() => EvalAltResult::ErrorAssignmentToConstant( + expr.get_constant_str(), expr.position(), - ))), + ) + .into(), + // Syntax error + expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(), } } @@ -1632,7 +1608,7 @@ impl Engine { self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .as_bool() - .map_err(|_| Box::new(EvalAltResult::ErrorLogicGuard(expr.position()))) + .map_err(|_| EvalAltResult::ErrorLogicGuard(expr.position()).into()) .and_then(|guard_val| { if guard_val { self.eval_stmt(scope, mods, state, lib, this_ptr, if_block, level) @@ -1665,9 +1641,7 @@ impl Engine { } } Ok(false) => return Ok(Default::default()), - Err(_) => { - return Err(Box::new(EvalAltResult::ErrorLogicGuard(expr.position()))) - } + Err(_) => return EvalAltResult::ErrorLogicGuard(expr.position()).into(), } }, @@ -1727,43 +1701,45 @@ impl Engine { state.scope_level -= 1; Ok(Default::default()) } else { - Err(Box::new(EvalAltResult::ErrorFor(x.1.position()))) + EvalAltResult::ErrorFor(x.1.position()).into() } } // Continue statement - Stmt::Continue(pos) => Err(Box::new(EvalAltResult::ErrorLoopBreak(false, *pos))), + Stmt::Continue(pos) => EvalAltResult::ErrorLoopBreak(false, *pos).into(), // Break statement - Stmt::Break(pos) => Err(Box::new(EvalAltResult::ErrorLoopBreak(true, *pos))), + Stmt::Break(pos) => EvalAltResult::ErrorLoopBreak(true, *pos).into(), // Return value Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Return => { let expr = x.1.as_ref().unwrap(); - Err(Box::new(EvalAltResult::Return( + EvalAltResult::Return( self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?, (x.0).1, - ))) + ) + .into() } // Empty return Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Return => { - Err(Box::new(EvalAltResult::Return(Default::default(), (x.0).1))) + EvalAltResult::Return(Default::default(), (x.0).1).into() } // Throw value Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Exception => { let expr = x.1.as_ref().unwrap(); let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; - Err(Box::new(EvalAltResult::ErrorRuntime( + EvalAltResult::ErrorRuntime( val.take_string().unwrap_or_else(|_| "".into()), (x.0).1, - ))) + ) + .into() } // Empty throw Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Exception => { - Err(Box::new(EvalAltResult::ErrorRuntime("".into(), (x.0).1))) + EvalAltResult::ErrorRuntime("".into(), (x.0).1).into() } Stmt::ReturnWithVal(_) => unreachable!(), @@ -1811,7 +1787,7 @@ impl Engine { // Guard against too many modules #[cfg(not(feature = "unchecked"))] if state.modules >= self.limits.max_modules { - return Err(Box::new(EvalAltResult::ErrorTooManyModules(*_pos))); + return EvalAltResult::ErrorTooManyModules(*_pos).into(); } if let Some(path) = self @@ -1830,13 +1806,13 @@ impl Engine { Ok(Default::default()) } else { - Err(Box::new(EvalAltResult::ErrorModuleNotFound( - path.to_string(), - expr.position(), - ))) + Err( + EvalAltResult::ErrorModuleNotFound(path.to_string(), expr.position()) + .into(), + ) } } else { - Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position()))) + EvalAltResult::ErrorImportExpr(expr.position()).into() } } @@ -1849,10 +1825,7 @@ impl Engine { let alias = rename.as_ref().map(|(n, _)| n).unwrap_or_else(|| id); scope.set_entry_alias(index, alias.clone()); } else { - return Err(Box::new(EvalAltResult::ErrorVariableNotFound( - id.into(), - *id_pos, - ))); + return EvalAltResult::ErrorVariableNotFound(id.into(), *id_pos).into(); } } Ok(Default::default()) @@ -1976,26 +1949,29 @@ impl Engine { let (arr, map, s) = calc_size(result.as_ref().unwrap()); if s > self.limits.max_string_size { - Err(Box::new(EvalAltResult::ErrorDataTooLarge( + EvalAltResult::ErrorDataTooLarge( "Length of string".to_string(), self.limits.max_string_size, s, Position::none(), - ))) + ) + .into() } else if arr > self.limits.max_array_size { - Err(Box::new(EvalAltResult::ErrorDataTooLarge( + EvalAltResult::ErrorDataTooLarge( "Size of array".to_string(), self.limits.max_array_size, arr, Position::none(), - ))) + ) + .into() } else if map > self.limits.max_map_size { - Err(Box::new(EvalAltResult::ErrorDataTooLarge( + EvalAltResult::ErrorDataTooLarge( "Number of properties in object map".to_string(), self.limits.max_map_size, map, Position::none(), - ))) + ) + .into() } else { result } @@ -2009,16 +1985,14 @@ impl Engine { #[cfg(not(feature = "unchecked"))] // Guard against too many operations if self.limits.max_operations > 0 && state.operations > self.limits.max_operations { - return Err(Box::new(EvalAltResult::ErrorTooManyOperations( - Position::none(), - ))); + return EvalAltResult::ErrorTooManyOperations(Position::none()).into(); } // Report progress - only in steps if let Some(progress) = &self.progress { if !progress(&state.operations) { // Terminate script if progress returns false - return Err(Box::new(EvalAltResult::ErrorTerminated(Position::none()))); + return EvalAltResult::ErrorTerminated(Position::none()).into(); } } diff --git a/src/fn_call.rs b/src/fn_call.rs index d93ba533..20557748 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -178,10 +178,11 @@ pub fn ensure_no_data_race( .enumerate() .find(|(_, a)| a.is_locked()) { - return Err(Box::new(EvalAltResult::ErrorDataRace( + return EvalAltResult::ErrorDataRace( format!("argument #{} of function '{}'", n + 1 + skip, fn_name), Position::none(), - ))); + ) + .into(); } } @@ -237,22 +238,22 @@ impl Engine { return Ok(match fn_name { KEYWORD_PRINT => ( (self.print)(result.as_str().map_err(|typ| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), typ.into(), Position::none(), - )) + ) })?) .into(), false, ), KEYWORD_DEBUG => ( (self.debug)(result.as_str().map_err(|typ| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), typ.into(), Position::none(), - )) + ) })?) .into(), false, @@ -276,56 +277,60 @@ impl Engine { // Getter function not found? if let Some(prop) = extract_prop_from_getter(fn_name) { - return Err(Box::new(EvalAltResult::ErrorDotExpr( + return EvalAltResult::ErrorDotExpr( format!( "Unknown property '{}' for {}, or it is write-only", prop, self.map_type_name(args[0].type_name()) ), Position::none(), - ))); + ) + .into(); } // Setter function not found? if let Some(prop) = extract_prop_from_setter(fn_name) { - return Err(Box::new(EvalAltResult::ErrorDotExpr( + return EvalAltResult::ErrorDotExpr( format!( "Unknown property '{}' for {}, or it is read-only", prop, self.map_type_name(args[0].type_name()) ), Position::none(), - ))); + ) + .into(); } // index getter function not found? #[cfg(not(feature = "no_index"))] if fn_name == FN_IDX_GET && args.len() == 2 { - return Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + return EvalAltResult::ErrorFunctionNotFound( format!( "{} [{}]", self.map_type_name(args[0].type_name()), self.map_type_name(args[1].type_name()), ), Position::none(), - ))); + ) + .into(); } // index setter function not found? #[cfg(not(feature = "no_index"))] if fn_name == FN_IDX_SET { - return Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + return EvalAltResult::ErrorFunctionNotFound( format!( "{} [{}]=", self.map_type_name(args[0].type_name()), self.map_type_name(args[1].type_name()), ), Position::none(), - ))); + ) + .into(); } // Raise error - Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + EvalAltResult::ErrorFunctionNotFound( format!( "{} ({})", fn_name, @@ -339,7 +344,8 @@ impl Engine { .join(", ") ), Position::none(), - ))) + ) + .into() } /// Call a script-defined function. @@ -400,17 +406,15 @@ impl Engine { // Convert return statement to return value EvalAltResult::Return(x, _) => Ok(x), EvalAltResult::ErrorInFunctionCall(name, err, _) => { - Err(Box::new(EvalAltResult::ErrorInFunctionCall( + EvalAltResult::ErrorInFunctionCall( format!("{} > {}", fn_name, name), err, Position::none(), - ))) + ) + .into() } - _ => Err(Box::new(EvalAltResult::ErrorInFunctionCall( - fn_name.to_string(), - err, - Position::none(), - ))), + _ => EvalAltResult::ErrorInFunctionCall(fn_name.to_string(), err, Position::none()) + .into(), }); // Remove all local variables @@ -482,20 +486,22 @@ impl Engine { KEYWORD_FN_PTR if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) => { - Err(Box::new(EvalAltResult::ErrorRuntime( + EvalAltResult::ErrorRuntime( "'Fn' should not be called in method style. Try Fn(...);".into(), Position::none(), - ))) + ) + .into() } // eval - reaching this point it must be a method-style call KEYWORD_EVAL if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) => { - Err(Box::new(EvalAltResult::ErrorRuntime( + EvalAltResult::ErrorRuntime( "'eval' should not be called in method style. Try eval(...);".into(), Position::none(), - ))) + ) + .into() } // Normal script function call @@ -783,11 +789,12 @@ impl Engine { return arg_value .take_immutable_string() .map_err(|typ| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), typ.into(), expr.position(), - )) + ) + .into() }) .and_then(|s| FnPtr::try_from(s)) .map(Into::::into) @@ -801,11 +808,12 @@ impl Engine { let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; if !fn_ptr.is::() { - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), self.map_type_name(fn_ptr.type_name()).into(), expr.position(), - ))); + ) + .into(); } let (fn_name, fn_curry) = fn_ptr.cast::().take_data(); @@ -855,11 +863,12 @@ impl Engine { // Recalculate hash hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty()); } else { - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( self.map_type_name(type_name::()).into(), fn_name.type_name().into(), expr.position(), - ))); + ) + .into(); } } @@ -1048,7 +1057,7 @@ impl Engine { } Some(f) => f.get_native_fn()(self, lib, args.as_mut()), None if def_val.is_some() => Ok(def_val.unwrap().into()), - None => Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + None => EvalAltResult::ErrorFunctionNotFound( format!( "{}{} ({})", modules, @@ -1063,7 +1072,8 @@ impl Engine { .join(", ") ), Position::none(), - ))), + ) + .into(), } } } diff --git a/src/fn_native.rs b/src/fn_native.rs index 149e720e..cc3ed0dc 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -175,10 +175,7 @@ impl TryFrom for FnPtr { if is_valid_identifier(value.chars()) { Ok(Self(value, Default::default())) } else { - Err(Box::new(EvalAltResult::ErrorFunctionNotFound( - value.into(), - Position::none(), - ))) + EvalAltResult::ErrorFunctionNotFound(value.into(), Position::none()).into() } } } diff --git a/src/module.rs b/src/module.rs index 57fe8eb5..b3bd5598 100644 --- a/src/module.rs +++ b/src/module.rs @@ -248,10 +248,7 @@ impl Module { hash_var: u64, ) -> Result<&mut Dynamic, Box> { self.all_variables.get_mut(&hash_var).ok_or_else(|| { - Box::new(EvalAltResult::ErrorVariableNotFound( - String::new(), - Position::none(), - )) + EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into() }) } @@ -1517,7 +1514,7 @@ mod stat { self.0 .get(path) .cloned() - .ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(path.into(), pos))) + .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(path.into(), pos).into()) } } } @@ -1597,10 +1594,7 @@ mod collection { } } - Err(Box::new(EvalAltResult::ErrorModuleNotFound( - path.into(), - pos, - ))) + EvalAltResult::ErrorModuleNotFound(path.into(), pos).into() } } } diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index d8e256cc..f40f1d11 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -17,7 +17,6 @@ use num_traits::{ use num_traits::float::Float; use crate::stdlib::{ - boxed::Box, fmt::Display, format, ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}, @@ -26,28 +25,31 @@ use crate::stdlib::{ // Checked add pub fn add(x: T, y: T) -> FuncReturn { x.checked_add(&y).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Addition overflow: {} + {}", x, y), Position::none(), - )) + ) + .into() }) } // Checked subtract pub fn sub(x: T, y: T) -> FuncReturn { x.checked_sub(&y).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Subtraction underflow: {} - {}", x, y), Position::none(), - )) + ) + .into() }) } // Checked multiply pub fn mul(x: T, y: T) -> FuncReturn { x.checked_mul(&y).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Multiplication overflow: {} * {}", x, y), Position::none(), - )) + ) + .into() }) } // Checked divide @@ -57,26 +59,26 @@ where { // Detect division by zero if y == T::zero() { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Division by zero: {} / {}", x, y), Position::none(), - ))); + ) + .into(); } x.checked_div(&y).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Division overflow: {} / {}", x, y), Position::none(), - )) + ) + .into() }) } // Checked negative - e.g. -(i32::MIN) will overflow i32::MAX pub fn neg(x: T) -> FuncReturn { x.checked_neg().ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( - format!("Negation overflow: -{}", x), - Position::none(), - )) + EvalAltResult::ErrorArithmetic(format!("Negation overflow: -{}", x), Position::none()) + .into() }) } // Checked absolute @@ -87,10 +89,8 @@ pub fn abs(x: T) -> FuncReturn { Ok(x) } else { x.checked_neg().ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( - format!("Negation overflow: -{}", x), - Position::none(), - )) + EvalAltResult::ErrorArithmetic(format!("Negation overflow: -{}", x), Position::none()) + .into() }) } } @@ -140,34 +140,38 @@ fn binary_xor(x: T, y: T) -> FuncReturn<::Output> { pub fn shl(x: T, y: INT) -> FuncReturn { // Cannot shift by a negative number of bits if y < 0 { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Left-shift by a negative number: {} << {}", x, y), Position::none(), - ))); + ) + .into(); } CheckedShl::checked_shl(&x, y as u32).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Left-shift by too many bits: {} << {}", x, y), Position::none(), - )) + ) + .into() }) } // Checked right-shift pub fn shr(x: T, y: INT) -> FuncReturn { // Cannot shift by a negative number of bits if y < 0 { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Right-shift by a negative number: {} >> {}", x, y), Position::none(), - ))); + ) + .into(); } CheckedShr::checked_shr(&x, y as u32).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Right-shift by too many bits: {} % {}", x, y), Position::none(), - )) + ) + .into() }) } // Unchecked left-shift - may panic if shifting by a negative number of bits @@ -181,10 +185,11 @@ pub fn shr_u>(x: T, y: T) -> FuncReturn<>::Output> { // Checked modulo pub fn modulo(x: T, y: T) -> FuncReturn { x.checked_rem(&y).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Modulo division by zero or overflow: {} % {}", x, y), Position::none(), - )) + ) + .into() }) } // Unchecked modulo - may panic if dividing by zero @@ -195,35 +200,40 @@ fn modulo_u(x: T, y: T) -> FuncReturn<::Output> { pub fn pow_i_i(x: INT, y: INT) -> FuncReturn { if cfg!(not(feature = "only_i32")) { if y > (u32::MAX as INT) { - Err(Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Integer raised to too large an index: {} ~ {}", x, y), Position::none(), - ))) + ) + .into() } else if y < 0 { - Err(Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Integer raised to a negative index: {} ~ {}", x, y), Position::none(), - ))) + ) + .into() } else { x.checked_pow(y as u32).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Power overflow: {} ~ {}", x, y), Position::none(), - )) + ) + .into() }) } } else { if y < 0 { - Err(Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Integer raised to a negative index: {} ~ {}", x, y), Position::none(), - ))) + ) + .into() } else { x.checked_pow(y as u32).ok_or_else(|| { - Box::new(EvalAltResult::ErrorArithmetic( + EvalAltResult::ErrorArithmetic( format!("Power overflow: {} ~ {}", x, y), Position::none(), - )) + ) + .into() }) } } @@ -242,10 +252,11 @@ pub fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn { pub fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn { // Raise to power that is larger than an i32 if y > (i32::MAX as INT) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Number raised to too large an index: {} ~ {}", x, y), Position::none(), - ))); + ) + .into(); } Ok(x.powi(y as i32)) diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 5574a4f5..fc6ca5ec 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -43,12 +43,13 @@ fn pad( && len > 0 && (len as usize) > _engine.limits.max_array_size { - return Err(Box::new(EvalAltResult::ErrorDataTooLarge( + return EvalAltResult::ErrorDataTooLarge( "Size of array".to_string(), _engine.limits.max_array_size, len as usize, Position::none(), - ))); + ) + .into(); } if len > 0 { diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index f8fd2d33..0818e8fe 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -12,7 +12,7 @@ use crate::{result::EvalAltResult, token::Position}; use num_traits::float::Float; #[cfg(not(feature = "no_float"))] -use crate::stdlib::{boxed::Box, format}; +use crate::stdlib::format; #[allow(dead_code)] #[cfg(feature = "only_i32")] @@ -109,10 +109,10 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { "to_int", |x: f32| { if x > (MAX_INT as f32) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Integer overflow: to_int({})", x), Position::none(), - ))); + ).into(); } Ok(x.trunc() as INT) @@ -122,10 +122,10 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { "to_int", |x: FLOAT| { if x > (MAX_INT as FLOAT) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Integer overflow: to_int({})", x), Position::none(), - ))); + ).into(); } Ok(x.trunc() as INT) diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 149823c4..0b58c19d 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -231,12 +231,12 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size { - return Err(Box::new(EvalAltResult::ErrorDataTooLarge( + return EvalAltResult::ErrorDataTooLarge( "Length of string".to_string(), _engine.limits.max_string_size, len as usize, Position::none(), - ))); + ).into(); } if len > 0 { @@ -254,12 +254,12 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str #[cfg(not(feature = "unchecked"))] if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size { - return Err(Box::new(EvalAltResult::ErrorDataTooLarge( + return EvalAltResult::ErrorDataTooLarge( "Length of string".to_string(), _engine.limits.max_string_size, s.len(), Position::none(), - ))); + ).into(); } } } diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index d554b68e..34f6821d 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -41,13 +41,13 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { #[cfg(not(feature = "unchecked"))] if seconds > (MAX_INT as u64) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!( "Integer overflow for timestamp duration: {}", -(seconds as i64) ), Position::none(), - ))); + ).into(); } return Ok(-(seconds as INT)); @@ -62,10 +62,10 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { #[cfg(not(feature = "unchecked"))] if seconds > (MAX_INT as u64) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Integer overflow for timestamp duration: {}", seconds), Position::none(), - ))); + ).into(); } return Ok(seconds as INT); @@ -92,10 +92,10 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { #[cfg(not(feature = "unchecked"))] if seconds > (MAX_INT as u64) { - return Err(Box::new(EvalAltResult::ErrorArithmetic( + return EvalAltResult::ErrorArithmetic( format!("Integer overflow for timestamp.elapsed: {}", seconds), Position::none(), - ))); + ).into(); } Ok(seconds as INT) diff --git a/src/result.rs b/src/result.rs index cecd14bd..40f2935c 100644 --- a/src/result.rs +++ b/src/result.rs @@ -361,3 +361,9 @@ impl EvalAltResult { self } } + +impl From for Result> { + fn from(err: EvalAltResult) -> Self { + Err(err.into()) + } +} diff --git a/src/serde/de.rs b/src/serde/de.rs index f6d328db..843c00d2 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -53,11 +53,12 @@ impl<'de> DynamicDeserializer<'de> { } /// Shortcut for a type conversion error. fn type_error_str(&self, error: &str) -> Result> { - Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( error.into(), self.value.type_name().into(), Position::none(), - ))) + ) + .into() } fn deserialize_int>( &mut self, @@ -134,10 +135,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>( impl Error for Box { fn custom(err: T) -> Self { - Box::new(EvalAltResult::ErrorParsing( - ParseErrorType::BadInput(err.to_string()), - Position::none(), - )) + EvalAltResult::ErrorParsing(ParseErrorType::BadInput(err.to_string()), Position::none()) } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index c11c7f1c..1f0d153d 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -99,10 +99,7 @@ pub fn to_dynamic(value: T) -> Result> impl Error for Box { fn custom(err: T) -> Self { - Box::new(EvalAltResult::ErrorRuntime( - err.to_string(), - Position::none(), - )) + EvalAltResult::ErrorRuntime(err.to_string(), Position::none()) } } @@ -298,22 +295,24 @@ impl Serializer for &mut DynamicSerializer { make_variant(_variant, content) } #[cfg(feature = "no_object")] - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( "Dynamic".into(), "map".into(), Position::none(), - ))); + ) + .into(); } fn serialize_seq(self, _len: Option) -> Result> { #[cfg(not(feature = "no_index"))] return Ok(DynamicSerializer::new(Array::new().into())); #[cfg(feature = "no_index")] - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( "Dynamic".into(), "array".into(), Position::none(), - ))); + ) + .into(); } fn serialize_tuple(self, len: usize) -> Result> { @@ -346,11 +345,12 @@ impl Serializer for &mut DynamicSerializer { let err_type = "map"; #[cfg(not(feature = "no_object"))] let err_type = "array"; - Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( "Dynamic".into(), err_type.into(), Position::none(), - ))) + ) + .into() } } @@ -358,11 +358,12 @@ impl Serializer for &mut DynamicSerializer { #[cfg(not(feature = "no_object"))] return Ok(DynamicSerializer::new(Map::new().into())); #[cfg(feature = "no_object")] - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( "Dynamic".into(), "map".into(), Position::none(), - ))); + ) + .into(); } fn serialize_struct( @@ -386,11 +387,12 @@ impl Serializer for &mut DynamicSerializer { map: Map::with_capacity(_len), }); #[cfg(feature = "no_object")] - return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + return EvalAltResult::ErrorMismatchOutputType( "Dynamic".into(), "map".into(), Position::none(), - ))); + ) + .into(); } } @@ -499,11 +501,11 @@ impl SerializeMap for DynamicSerializer { let key = mem::take(&mut self._key) .take_immutable_string() .map_err(|typ| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( "string".into(), typ.into(), Position::none(), - )) + ) })?; let _value = _value.serialize(&mut *self)?; let map = self._value.downcast_mut::().unwrap(); @@ -523,11 +525,11 @@ impl SerializeMap for DynamicSerializer { { let _key: Dynamic = _key.serialize(&mut *self)?; let _key = _key.take_immutable_string().map_err(|typ| { - Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( "string".into(), typ.into(), Position::none(), - )) + ) })?; let _value = _value.serialize(&mut *self)?; let map = self._value.downcast_mut::().unwrap(); diff --git a/src/serde/str.rs b/src/serde/str.rs index 7fb1c9cc..8283cc79 100644 --- a/src/serde/str.rs +++ b/src/serde/str.rs @@ -20,11 +20,12 @@ impl<'a> ImmutableStringDeserializer<'a> { } /// Shortcut for a type conversion error. fn type_error(&self) -> Result> { - Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchOutputType( type_name::().into(), "string".into(), Position::none(), - ))) + ) + .into() } } From c55435ce817e8af490c84c7d22194476692a28da Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 10:38:31 +0800 Subject: [PATCH 08/13] no_closure when no_function. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 73cc5b2e..df785e3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ only_i32 = [] # set INT=i32 (useful for 32-bit systems) only_i64 = [] # set INT=i64 (default) and disable support for all other integer types no_index = [] # no arrays and indexing no_object = [] # no custom objects -no_function = [] # no script-defined functions +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 From efe964f0096cc63cf6a0b57e3ac418393a3ced4f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 21:10:41 +0800 Subject: [PATCH 09/13] Fix writeup. --- doc/src/rust/register-raw.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/doc/src/rust/register-raw.md b/doc/src/rust/register-raw.md index b666d588..b7069ce3 100644 --- a/doc/src/rust/register-raw.md +++ b/doc/src/rust/register-raw.md @@ -95,10 +95,11 @@ When there is a mutable reference to the `this` object (i.e. the first argument) there can be no other immutable references to `args`, otherwise the Rust borrow checker will complain. -Example - Passing a Function Pointer to a Rust Function ------------------------------------------------------- +Example - Passing a Callback to a Rust Function +---------------------------------------------- -The low-level API is useful when there is a need to interact with the scripting [`Engine`] within a function. +The low-level API is useful when there is a need to interact with the scripting [`Engine`] +within a function. The following example registers a function that takes a [function pointer] as an argument, then calls it within the same [`Engine`]. This way, a _callback_ function can be provided @@ -140,6 +141,24 @@ let result = engine.eval::(r#" ``` +TL;DR - Why `read_lock` and `write_lock` +--------------------------------------- + +The `Dynamic` API that casts it to a reference to a particular data type is `read_lock` +(for an immutable reference) and `write_lock` (for a mutable reference). + +As the naming shows, something is _locked_ in order to allow this access, and that something +is a _shared value_ created by [capturing][automatic currying] variables from [closures]. + +Shared values are implemented as `Rc>` (`Arc>` under [`sync`]). + +If the value is _not_ a shared value, or if running under [`no_closure`] where there is +no [capturing][automatic currying], this API de-sugars to a simple `downcast_ref` and `downcast_mut`. + +If the value is a shared value, then it is first locked and the returned lock guard +then allows access to the underlying value in the specified type. + + Hold Multiple References ------------------------ @@ -152,9 +171,9 @@ to partition the slice: let (first, rest) = args.split_at_mut(1); // Mutable reference to the first parameter -let this_ptr = first[0].downcast_mut::().unwrap(); +let this_ptr: &mut Dynamic = &mut *first[0].write_lock::().unwrap(); // Immutable reference to the second value parameter // This can be mutable but there is no point because the parameter is passed by value -let value_ref = rest[0].read_lock::().unwrap(); +let value_ref: &Dynamic = &*rest[0].read_lock::().unwrap(); ``` From b8b1efd2413bc23cf20372543ea3881a4b399fb6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 21:11:24 +0800 Subject: [PATCH 10/13] Add note on `&T` parameters. --- doc/src/language/method.md | 6 ++++-- doc/src/rust/custom.md | 6 ++++-- doc/src/rust/getters-setters.md | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/src/language/method.md b/doc/src/language/method.md index 290d1a06..3b8a82d4 100644 --- a/doc/src/language/method.md +++ b/doc/src/language/method.md @@ -36,6 +36,8 @@ update(array[0]); // <- 'array[0]' is an expression returning a calculated val array[0].update(); // <- call in method-call style will update 'a' ``` +**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** + Number of Parameters -------------------- @@ -51,8 +53,8 @@ The following table illustrates the differences: | Rhai script | _n_ | `this` | `fn method(x, y) {}` | -`&mut` is Efficient (Except for `ImmutableString`) ------------------------------------------------- +`&mut` is Efficient, Except for `ImmutableString` +----------------------------------------------- Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone, even when the intention is not to mutate that argument, because it avoids cloning that argument value. diff --git a/doc/src/rust/custom.md b/doc/src/rust/custom.md index 3e6b5ca3..b2325204 100644 --- a/doc/src/rust/custom.md +++ b/doc/src/rust/custom.md @@ -83,6 +83,8 @@ engine ***Note**: Rhai follows the convention that methods of custom types take a `&mut` first parameter so that invoking methods can update the types. All other parameters in Rhai are passed by value (i.e. clones).* +**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** + Use the Custom Type in Scripts ----------------------------- @@ -125,8 +127,8 @@ Under [`no_object`], however, the _method_ style of function calls let result = engine.eval::<()>("let x = [1, 2, 3]; x.clear()")?; ``` -[`type_of()`] -------------- +`type_of()` a Custom Type +------------------------- [`type_of()`] works fine with custom types and returns the name of the type. diff --git a/doc/src/rust/getters-setters.md b/doc/src/rust/getters-setters.md index 4c44399d..7597e8d5 100644 --- a/doc/src/rust/getters-setters.md +++ b/doc/src/rust/getters-setters.md @@ -42,3 +42,5 @@ let result = engine.eval::(r#"let a = new_ts(); a.xyz = "42"; a.xyz"#)?; println!("Answer: {}", result); // prints 42 ``` + +**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** From 130bcfe2931839f067005b7a17c787a4db5d89f7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 21:19:54 +0800 Subject: [PATCH 11/13] Fix serde. --- src/serde/de.rs | 1 + src/serde/ser.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index 843c00d2..6b0b8a53 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -136,6 +136,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>( impl Error for Box { fn custom(err: T) -> Self { EvalAltResult::ErrorParsing(ParseErrorType::BadInput(err.to_string()), Position::none()) + .into() } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 1f0d153d..e13e22ec 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -99,7 +99,7 @@ pub fn to_dynamic(value: T) -> Result> impl Error for Box { fn custom(err: T) -> Self { - EvalAltResult::ErrorRuntime(err.to_string(), Position::none()) + EvalAltResult::ErrorRuntime(err.to_string(), Position::none()).into() } } From 261a1f3f66b748d3c60512895052d4e6961e7ed2 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 22:36:36 +0800 Subject: [PATCH 12/13] Do not run doc tests for only_i32. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4a476a3..8c8b19eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - "--features sync" - "--features no_optimize" - "--features no_float" - - "--features only_i32" + - "--tests --features only_i32" - "--features only_i64" - "--features no_index" - "--features no_object" From b604ea3e9389534950737ef6540d674a1e48e0d9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 6 Aug 2020 22:47:10 +0800 Subject: [PATCH 13/13] Fix serde doc test. --- src/serde/ser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serde/ser.rs b/src/serde/ser.rs index e13e22ec..f1a2ab77 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -85,9 +85,9 @@ impl DynamicSerializer { /// assert!(value.is::()); /// /// let map = value.cast::(); -/// let point = map.get("d").unwrap().downcast_ref::().unwrap(); -/// assert_eq!(*point.get("x").unwrap().downcast_ref::().unwrap(), 123.456); -/// assert_eq!(*point.get("y").unwrap().downcast_ref::().unwrap(), 999.0); +/// let point = map["d"].read_lock::().unwrap(); +/// assert_eq!(*point["x"].read_lock::().unwrap(), 123.456); +/// assert_eq!(*point["y"].read_lock::().unwrap(), 999.0); /// # } /// # Ok(()) /// # }