From a5d4a0abb98675b9dab06c44a94d80f16036babd Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 25 Apr 2021 15:27:58 +0800 Subject: [PATCH] Disable on_progress with unchecked. --- CHANGELOG.md | 1 + src/engine.rs | 106 ++++++++++++++++++++++------------------------ src/engine_api.rs | 1 + src/fn_call.rs | 18 +++++--- src/fn_native.rs | 2 + 5 files changed, 66 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 235048e2..d8f6f26e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Breaking changes * `Dynamic::is_shared` and `Dynamic::is_locked` are removed under the `no_closure` feature. They used to always return `false`. * `Engine::call_fn` now evaluates the `AST` before calling the function. +* `Engine::on_progress` is disabled with `unchecked`. Enhancements ------------ diff --git a/src/engine.rs b/src/engine.rs index dfbe507d..f85d5b66 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -3,8 +3,7 @@ use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt}; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::fn_native::{ - CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback, - OnVarCallback, + CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnVarCallback, }; use crate::module::NamespaceRef; use crate::optimize::OptimizationLevel; @@ -775,7 +774,8 @@ pub struct Engine { /// Callback closure for implementing the `debug` command. pub(crate) debug: OnDebugCallback, /// Callback closure for progress reporting. - pub(crate) progress: Option, + #[cfg(not(feature = "unchecked"))] + pub(crate) progress: Option, /// Optimize the AST after compilation. pub(crate) optimization_level: OptimizationLevel, @@ -879,6 +879,7 @@ impl Engine { debug: Box::new(default_debug), // progress callback + #[cfg(not(feature = "unchecked"))] progress: None, // optimization level @@ -939,6 +940,8 @@ impl Engine { print: Box::new(|_| {}), debug: Box::new(|_, _, _| {}), + + #[cfg(not(feature = "unchecked"))] progress: None, optimization_level: if cfg!(feature = "no_optimize") { @@ -1459,8 +1462,9 @@ impl Engine { match lhs { // id.??? or id[???] - Expr::Variable(_, var_pos, x) => { - self.inc_operations(state, *var_pos)?; + Expr::Variable(_, _var_pos, x) => { + #[cfg(not(feature = "unchecked"))] + self.inc_operations(state, *_var_pos)?; let (target, pos) = self.search_namespace(scope, mods, state, lib, this_ptr, lhs)?; @@ -1511,6 +1515,7 @@ impl Engine { size: usize, level: usize, ) -> Result<(), Box> { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, expr.position())?; match expr { @@ -1620,6 +1625,7 @@ impl Engine { _indexers: bool, _level: usize, ) -> Result, Box> { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, Position::NONE)?; match target { @@ -1654,18 +1660,15 @@ impl Engine { }; #[cfg(feature = "unchecked")] let arr_idx = if index < 0 { + // Count from end if negative arr_len - index.abs() as usize } else { index as usize }; - #[cfg(not(feature = "unchecked"))] - return arr.get_mut(arr_idx).map(Target::from).ok_or_else(|| { - EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into() - }); - - #[cfg(feature = "unchecked")] - return Ok(Target::from(&mut arr[arr_idx])); + arr.get_mut(arr_idx) + .map(Target::from) + .ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()) } #[cfg(not(feature = "no_object"))] @@ -1679,26 +1682,26 @@ impl Engine { map.insert(index.clone().into(), Default::default()); } - return Ok(map + Ok(map .get_mut(index.as_str()) .map(Target::from) - .unwrap_or_else(|| Target::from(()))); + .unwrap_or_else(|| Target::from(Dynamic::UNIT))) } #[cfg(not(feature = "no_index"))] Dynamic(Union::Str(s, _)) => { // val_string[idx] - let _chars_len = s.chars().count(); let index = _idx .as_int() .map_err(|err| self.make_type_mismatch_err::(err, idx_pos))?; - #[cfg(not(feature = "unchecked"))] let (ch, offset) = if index >= 0 { + // Count from end if negative let offset = index as usize; ( s.chars().nth(offset).ok_or_else(|| { - EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos) + let chars_len = s.chars().count(); + EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos) })?, offset, ) @@ -1706,24 +1709,17 @@ impl Engine { let offset = index as usize; ( s.chars().rev().nth(offset - 1).ok_or_else(|| { - EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos) + let chars_len = s.chars().count(); + EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos) })?, offset, ) } else { - return EvalAltResult::ErrorStringBounds(_chars_len, index, idx_pos).into(); + let chars_len = s.chars().count(); + return EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos).into(); }; - #[cfg(feature = "unchecked")] - let (ch, offset) = if index >= 0 { - let offset = index as usize; - (s.chars().nth(offset).unwrap(), offset) - } else { - let offset = index.abs() as usize; - (s.chars().rev().nth(offset - 1).unwrap(), offset) - }; - - return Ok(Target::StringChar(target, offset, ch.into())); + Ok(Target::StringChar(target, offset, ch.into())) } #[cfg(not(feature = "no_index"))] @@ -1733,32 +1729,27 @@ impl Engine { let hash_get = FnCallHashes::from_native(calc_fn_hash(std::iter::empty(), FN_IDX_GET, 2)); - return self - .exec_fn_call( - _mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos, - None, _level, - ) - .map(|(v, _)| v.into()) - .map_err(|err| match *err { - EvalAltResult::ErrorFunctionNotFound(fn_sig, _) - if fn_sig.ends_with(']') => - { - Box::new(EvalAltResult::ErrorIndexingType( - type_name.into(), - Position::NONE, - )) - } - _ => err, - }); + self.exec_fn_call( + _mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos, None, + _level, + ) + .map(|(v, _)| v.into()) + .map_err(|err| match *err { + EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.ends_with(']') => { + Box::new(EvalAltResult::ErrorIndexingType( + type_name.into(), + Position::NONE, + )) + } + _ => err, + }) } - _ => { - return EvalAltResult::ErrorIndexingType( - self.map_type_name(target.type_name()).into(), - Position::NONE, - ) - .into() - } + _ => EvalAltResult::ErrorIndexingType( + self.map_type_name(target.type_name()).into(), + Position::NONE, + ) + .into(), } } @@ -1773,6 +1764,7 @@ impl Engine { expr: &Expr, level: usize, ) -> RhaiResult { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, expr.position())?; let result = match expr { @@ -2110,6 +2102,7 @@ impl Engine { stmt: &Stmt, level: usize, ) -> RhaiResult { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, stmt.position())?; let result = match stmt { @@ -2138,6 +2131,7 @@ impl Engine { .into(); } + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, pos)?; if lhs_ptr.is_read_only() { @@ -2332,7 +2326,6 @@ impl Engine { // For loop Stmt::For(expr, x, _) => { let (Ident { name, .. }, statements) = x.as_ref(); - let pos = statements.position(); let iter_obj = self .eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten(); @@ -2386,7 +2379,8 @@ impl Engine { *loop_var = value; } - self.inc_operations(state, pos)?; + #[cfg(not(feature = "unchecked"))] + self.inc_operations(state, statements.position())?; if statements.is_empty() { continue; @@ -2828,6 +2822,7 @@ impl Engine { } /// Check if the number of operations stay within limit. + #[cfg(not(feature = "unchecked"))] pub(crate) fn inc_operations( &self, state: &mut State, @@ -2835,7 +2830,6 @@ impl Engine { ) -> Result<(), Box> { state.operations += 1; - #[cfg(not(feature = "unchecked"))] // Guard against too many operations if self.max_operations() > 0 && state.operations > self.max_operations() { return EvalAltResult::ErrorTooManyOperations(pos).into(); diff --git a/src/engine_api.rs b/src/engine_api.rs index e73accdc..1722dd76 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -2105,6 +2105,7 @@ impl Engine { /// # Ok(()) /// # } /// ``` + #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn on_progress( &mut self, diff --git a/src/fn_call.rs b/src/fn_call.rs index 896e934a..fff4dfb6 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -294,6 +294,7 @@ impl Engine { is_op_assignment: bool, pos: Position, ) -> Result<(Dynamic, bool), Box> { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, pos)?; let state_source = state.source.clone(); @@ -483,6 +484,7 @@ impl Engine { .into() } + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, pos)?; if fn_def.body.is_empty() { @@ -844,10 +846,11 @@ impl Engine { state: &mut State, lib: &[&Module], script: &str, - pos: Position, + _pos: Position, level: usize, ) -> RhaiResult { - self.inc_operations(state, pos)?; + #[cfg(not(feature = "unchecked"))] + self.inc_operations(state, _pos)?; let script = script.trim(); if script.is_empty() { @@ -1305,14 +1308,15 @@ impl Engine { .chain(constant_args.iter().map(|(v, _)| Ok(v.clone()))) .collect::>()?; - let (mut target, pos) = + let (mut target, _pos) = self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?; if target.as_ref().is_read_only() { target = target.into_owned(); } - self.inc_operations(state, pos)?; + #[cfg(not(feature = "unchecked"))] + self.inc_operations(state, _pos)?; #[cfg(not(feature = "no_closure"))] let target_is_shared = target.is_shared(); @@ -1396,10 +1400,11 @@ impl Engine { .collect::>()?; // Get target reference to first argument - let (target, pos) = + let (target, _pos) = self.search_scope_only(scope, mods, state, lib, this_ptr, &args_expr[0])?; - self.inc_operations(state, pos)?; + #[cfg(not(feature = "unchecked"))] + self.inc_operations(state, _pos)?; #[cfg(not(feature = "no_closure"))] let target_is_shared = target.is_shared(); @@ -1439,6 +1444,7 @@ impl Engine { let func = match module.get_qualified_fn(hash) { // Then search in Rust functions None => { + #[cfg(not(feature = "unchecked"))] self.inc_operations(state, pos)?; let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id())); diff --git a/src/fn_native.rs b/src/fn_native.rs index 007ba761..a72d79b0 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -418,9 +418,11 @@ pub type FnPlugin = dyn PluginFunction; pub type FnPlugin = dyn PluginFunction + Send + Sync; /// A standard callback function for progress reporting. +#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "sync"))] pub type OnProgressCallback = Box Option + 'static>; /// A standard callback function for progress reporting. +#[cfg(not(feature = "unchecked"))] #[cfg(feature = "sync")] pub type OnProgressCallback = Box Option + Send + Sync + 'static>;