diff --git a/src/api/limits.rs b/src/api/limits.rs index 70de6592..8f6f2be9 100644 --- a/src/api/limits.rs +++ b/src/api/limits.rs @@ -1,12 +1,31 @@ //! Settings for [`Engine`]'s limitations. #![cfg(not(feature = "unchecked"))] -use super::default_limits; use crate::Engine; use std::num::{NonZeroU64, NonZeroUsize}; #[cfg(feature = "no_std")] use std::prelude::v1::*; +pub mod default_limits { + #[cfg(debug_assertions)] + #[cfg(not(feature = "no_function"))] + pub const MAX_CALL_STACK_DEPTH: usize = 8; + #[cfg(debug_assertions)] + pub const MAX_EXPR_DEPTH: usize = 32; + #[cfg(not(feature = "no_function"))] + #[cfg(debug_assertions)] + pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16; + + #[cfg(not(debug_assertions))] + #[cfg(not(feature = "no_function"))] + pub const MAX_CALL_STACK_DEPTH: usize = 64; + #[cfg(not(debug_assertions))] + pub const MAX_EXPR_DEPTH: usize = 64; + #[cfg(not(feature = "no_function"))] + #[cfg(not(debug_assertions))] + pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32; +} + /// A type containing all the limits imposed by the [`Engine`]. /// /// Not available under `unchecked`. diff --git a/src/api/mod.rs b/src/api/mod.rs index d98b0dd6..c296c81e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -43,28 +43,7 @@ use std::prelude::v1::*; pub mod default_limits { #[cfg(not(feature = "unchecked"))] - #[cfg(debug_assertions)] - #[cfg(not(feature = "no_function"))] - pub const MAX_CALL_STACK_DEPTH: usize = 8; - #[cfg(not(feature = "unchecked"))] - #[cfg(debug_assertions)] - pub const MAX_EXPR_DEPTH: usize = 32; - #[cfg(not(feature = "unchecked"))] - #[cfg(not(feature = "no_function"))] - #[cfg(debug_assertions)] - pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16; - - #[cfg(not(feature = "unchecked"))] - #[cfg(not(debug_assertions))] - #[cfg(not(feature = "no_function"))] - pub const MAX_CALL_STACK_DEPTH: usize = 64; - #[cfg(not(feature = "unchecked"))] - #[cfg(not(debug_assertions))] - pub const MAX_EXPR_DEPTH: usize = 64; - #[cfg(not(feature = "unchecked"))] - #[cfg(not(feature = "no_function"))] - #[cfg(not(debug_assertions))] - pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32; + pub use super::limits::default_limits::*; pub const MAX_DYNAMIC_PARAMETERS: usize = 16; } @@ -236,55 +215,3 @@ impl Engine { self } } - -#[cfg(feature = "unchecked")] -impl Engine { - /// The maximum levels of function calls allowed for a script. - #[inline(always)] - #[must_use] - pub const fn max_call_levels(&self) -> usize { - usize::MAX - } - /// The maximum number of operations allowed for a script to run (0 for unlimited). - #[inline] - #[must_use] - pub const fn max_operations(&self) -> u64 { - 0 - } - /// The maximum number of imported [modules][crate::Module] allowed for a script. - #[inline(always)] - #[must_use] - pub const fn max_modules(&self) -> usize { - usize::MAX - } - /// The depth limit for expressions (0 for unlimited). - #[inline(always)] - #[must_use] - pub const fn max_expr_depth(&self) -> usize { - 0 - } - /// The depth limit for expressions in functions (0 for unlimited). - #[inline(always)] - #[must_use] - pub const fn max_function_expr_depth(&self) -> usize { - 0 - } - /// The maximum length of [strings][crate::ImmutableString] (0 for unlimited). - #[inline(always)] - #[must_use] - pub const fn max_string_size(&self) -> usize { - 0 - } - /// The maximum length of [arrays][crate::Array] (0 for unlimited). - #[inline(always)] - #[must_use] - pub const fn max_array_size(&self) -> usize { - 0 - } - /// The maximum size of [object maps][crate::Map] (0 for unlimited). - #[inline(always)] - #[must_use] - pub const fn max_map_size(&self) -> usize { - 0 - } -} diff --git a/src/engine.rs b/src/engine.rs index cb4cb094..68ec87cc 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -347,9 +347,9 @@ impl Engine { } /// Check a result to ensure that it is valid. + #[cfg(not(feature = "unchecked"))] #[inline] pub(crate) fn check_return_value(&self, result: RhaiResult, _pos: Position) -> RhaiResult { - #[cfg(not(feature = "unchecked"))] if let Ok(ref r) = result { self.check_data_size(r, _pos)?; } @@ -357,3 +357,81 @@ impl Engine { result } } + +#[cfg(feature = "unchecked")] +impl Engine { + /// The maximum levels of function calls allowed for a script. + #[inline(always)] + #[must_use] + pub const fn max_call_levels(&self) -> usize { + usize::MAX + } + /// The maximum number of operations allowed for a script to run (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_operations(&self) -> u64 { + 0 + } + /// The maximum number of imported [modules][crate::Module] allowed for a script. + #[inline(always)] + #[must_use] + pub const fn max_modules(&self) -> usize { + usize::MAX + } + /// The depth limit for expressions (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_expr_depth(&self) -> usize { + 0 + } + /// The depth limit for expressions in functions (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_function_expr_depth(&self) -> usize { + 0 + } + /// The maximum length of [strings][crate::ImmutableString] (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_string_size(&self) -> usize { + 0 + } + /// The maximum length of [arrays][crate::Array] (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_array_size(&self) -> usize { + 0 + } + /// The maximum size of [object maps][crate::Map] (0 for unlimited). + #[inline(always)] + #[must_use] + pub const fn max_map_size(&self) -> usize { + 0 + } + + /// Check if the number of operations stay within limit. + #[inline(always)] + pub(crate) const fn track_operation( + &self, + _: &crate::GlobalRuntimeState, + _: Position, + ) -> crate::RhaiResultOf<()> { + Ok(()) + } + + /// Check whether the size of a [`Dynamic`] is within limits. + #[inline(always)] + pub(crate) const fn check_data_size( + &self, + _: &Dynamic, + _: Position, + ) -> crate::RhaiResultOf<()> { + Ok(()) + } + + /// Check a result to ensure that it is valid. + #[inline(always)] + pub(crate) const fn check_return_value(&self, result: RhaiResult, _: Position) -> RhaiResult { + result + } +} diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 2b9d6425..78acb0ff 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -131,7 +131,6 @@ impl Engine { self.eval_op_assignment( global, caches, lib, op_info, obj_ptr, root, new_val, level, )?; - #[cfg(not(feature = "unchecked"))] self.check_data_size(obj_ptr, op_info.pos)?; None } @@ -159,7 +158,6 @@ impl Engine { )?; // Replace new value new_val = val.take_or_clone(); - #[cfg(not(feature = "unchecked"))] self.check_data_size(&new_val, op_info.pos)?; } } @@ -246,7 +244,6 @@ impl Engine { global, caches, lib, op_info, val_target, root, new_val, level, )?; } - #[cfg(not(feature = "unchecked"))] self.check_data_size(target.source(), op_info.pos)?; Ok((Dynamic::UNIT, true)) } @@ -606,9 +603,7 @@ impl Engine { Expr::Variable(x, .., var_pos) => { #[cfg(feature = "debugging")] self.run_debugger(scope, global, lib, this_ptr, lhs, level)?; - - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, *var_pos)?; + self.track_operation(global, *var_pos)?; let (mut target, ..) = self.search_namespace(scope, global, lib, this_ptr, lhs, level)?; @@ -655,8 +650,7 @@ impl Engine { idx_values: &mut FnArgsVec, level: usize, ) -> RhaiResultOf<()> { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, expr.position())?; + self.track_operation(global, expr.position())?; match expr { #[cfg(not(feature = "no_object"))] @@ -814,8 +808,7 @@ impl Engine { use_indexers: bool, level: usize, ) -> RhaiResultOf> { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, Position::NONE)?; + self.track_operation(global, Position::NONE)?; match target { #[cfg(not(feature = "no_index"))] diff --git a/src/eval/data_check.rs b/src/eval/data_check.rs index 293b1d99..377a7757 100644 --- a/src/eval/data_check.rs +++ b/src/eval/data_check.rs @@ -1,6 +1,7 @@ //! Data size checks during evaluation. #![cfg(not(feature = "unchecked"))] +use super::GlobalRuntimeState; use crate::types::dynamic::Union; use crate::{Dynamic, Engine, Position, RhaiResultOf, ERR}; use std::num::NonZeroUsize; @@ -15,7 +16,6 @@ impl Engine { /// # Panics /// /// Panics if any interior data is shared (should never happen). - #[cfg(not(feature = "unchecked"))] pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) { match value.0 { #[cfg(not(feature = "no_index"))] @@ -71,24 +71,11 @@ impl Engine { } /// Is there a data size limit set? - #[cfg(not(feature = "unchecked"))] pub(crate) const fn has_data_size_limit(&self) -> bool { - let mut _limited = self.limits.max_string_size.is_some(); - - #[cfg(not(feature = "no_index"))] - { - _limited = _limited || self.limits.max_array_size.is_some(); - } - #[cfg(not(feature = "no_object"))] - { - _limited = _limited || self.limits.max_map_size.is_some(); - } - - _limited + self.max_string_size() > 0 || self.max_array_size() > 0 || self.max_map_size() > 0 } /// Raise an error if any data size exceeds limit. - #[cfg(not(feature = "unchecked"))] pub(crate) fn raise_err_if_over_data_size_limit( &self, sizes: (usize, usize, usize), @@ -128,7 +115,6 @@ impl Engine { } /// Check whether the size of a [`Dynamic`] is within limits. - #[cfg(not(feature = "unchecked"))] pub(crate) fn check_data_size(&self, value: &Dynamic, pos: Position) -> RhaiResultOf<()> { // If no data size limits, just return if !self.has_data_size_limit() { @@ -143,29 +129,30 @@ impl Engine { /// Raise an error if the size of a [`Dynamic`] is out of limits (if any). /// /// Not available under `unchecked`. - #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn ensure_data_size_within_limits(&self, value: &Dynamic) -> RhaiResultOf<()> { self.check_data_size(value, Position::NONE) } /// Check if the number of operations stay within limit. - #[cfg(not(feature = "unchecked"))] - pub(crate) fn inc_operations( + pub(crate) fn track_operation( &self, - num_operations: &mut u64, + global: &mut GlobalRuntimeState, pos: Position, ) -> RhaiResultOf<()> { - *num_operations += 1; + global.num_operations += 1; // Guard against too many operations - if self.max_operations() > 0 && *num_operations > self.max_operations() { + let max = self.max_operations(); + let num_operations = global.num_operations; + + if max > 0 && num_operations > max { return Err(ERR::ErrorTooManyOperations(pos).into()); } // Report progress - only in steps if let Some(ref progress) = self.progress { - if let Some(token) = progress(*num_operations) { + if let Some(token) = progress(num_operations) { // Terminate script if progress returns a termination token return Err(ERR::ErrorTerminated(token, pos).into()); } diff --git a/src/eval/expr.rs b/src/eval/expr.rs index c965ddda..ce34a8ad 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -318,8 +318,7 @@ impl Engine { let reset_debugger = self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?; - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, expr.position())?; + self.track_operation(global, expr.position())?; let result = self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level); @@ -337,8 +336,7 @@ impl Engine { #[cfg(feature = "debugging")] self.run_debugger(scope, global, lib, this_ptr, expr, level)?; - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, expr.position())?; + self.track_operation(global, expr.position())?; return if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS { this_ptr @@ -355,8 +353,7 @@ impl Engine { let reset_debugger = self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?; - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, expr.position())?; + self.track_operation(global, expr.position())?; let result = match expr { // Constants @@ -410,7 +407,7 @@ impl Engine { let mut result = Ok(Dynamic::UNIT); #[cfg(not(feature = "unchecked"))] - let mut sizes = (0, 0, 0); + let mut total_data_sizes = (0, 0, 0); for item_expr in &**x { let value = match self @@ -424,19 +421,21 @@ impl Engine { }; #[cfg(not(feature = "unchecked"))] - let val_sizes = Self::calc_data_sizes(&value, true); + if self.has_data_size_limit() { + let val_sizes = Self::calc_data_sizes(&value, true); + + total_data_sizes = ( + total_data_sizes.0 + val_sizes.0, + total_data_sizes.1 + val_sizes.1, + total_data_sizes.2 + val_sizes.2, + ); + self.raise_err_if_over_data_size_limit( + total_data_sizes, + item_expr.position(), + )?; + } array.push(value); - - #[cfg(not(feature = "unchecked"))] - if self.has_data_size_limit() { - sizes = ( - sizes.0 + val_sizes.0, - sizes.1 + val_sizes.1, - sizes.2 + val_sizes.2, - ); - self.raise_err_if_over_data_size_limit(sizes, item_expr.position())?; - } } result.map(|_| array.into()) @@ -448,7 +447,7 @@ impl Engine { let mut result = Ok(Dynamic::UNIT); #[cfg(not(feature = "unchecked"))] - let mut sizes = (0, 0, 0); + let mut total_data_sizes = (0, 0, 0); for (key, value_expr) in &x.0 { let value = match self @@ -462,15 +461,20 @@ impl Engine { }; #[cfg(not(feature = "unchecked"))] - let delta = Self::calc_data_sizes(&value, true); + if self.has_data_size_limit() { + let delta = Self::calc_data_sizes(&value, true); + total_data_sizes = ( + total_data_sizes.0 + delta.0, + total_data_sizes.1 + delta.1, + total_data_sizes.2 + delta.2, + ); + self.raise_err_if_over_data_size_limit( + total_data_sizes, + value_expr.position(), + )?; + } *map.get_mut(key.as_str()).unwrap() = value; - - #[cfg(not(feature = "unchecked"))] - if self.has_data_size_limit() { - sizes = (sizes.0 + delta.0, sizes.1 + delta.1, sizes.2 + delta.2); - self.raise_err_if_over_data_size_limit(sizes, value_expr.position())?; - } } result.map(|_| map.into()) diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index d62a39bb..726b661f 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -152,7 +152,6 @@ impl Engine { let context = (self, op, None, &*global, lib, *op_pos, level).into(); let result = func(context, args).map(|_| ()); - #[cfg(not(feature = "unchecked"))] self.check_data_size(args[0], root.1)?; return result; @@ -165,10 +164,7 @@ impl Engine { match self.call_native_fn( global, caches, lib, op_assign, hash, args, true, true, *op_pos, level, ) { - Ok(_) => { - #[cfg(not(feature = "unchecked"))] - self.check_data_size(args[0], root.1)?; - } + Ok(_) => self.check_data_size(args[0], root.1)?, Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) => { // Expand to `var = var op rhs` @@ -218,8 +214,7 @@ impl Engine { // Function calls should account for a relatively larger portion of statements. if let Stmt::FnCall(x, ..) = stmt { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, stmt.position())?; + self.track_operation(global, stmt.position())?; let result = self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level); @@ -236,8 +231,7 @@ impl Engine { if let Stmt::Assignment(x, ..) = stmt { let (op_info, BinaryExpr { lhs, rhs }) = &**x; - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, stmt.position())?; + self.track_operation(global, stmt.position())?; let result = if let Expr::Variable(x, ..) = lhs { let rhs_result = self @@ -267,8 +261,7 @@ impl Engine { ); } - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, pos)?; + self.track_operation(global, pos)?; let root = (var_name, pos); let lhs_ptr = &mut lhs_ptr; @@ -339,8 +332,7 @@ impl Engine { return result; } - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, stmt.position())?; + self.track_operation(global, stmt.position())?; let result = match stmt { // No-op @@ -512,8 +504,7 @@ impl Engine { let (.., body) = &**x; if body.is_empty() { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, body.position())?; + self.track_operation(global, body.position())?; } else { match self .eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level) @@ -668,10 +659,7 @@ impl Engine { *scope.get_mut_by_index(index).write_lock().unwrap() = value; - #[cfg(not(feature = "unchecked"))] - if let Err(err) = self - .inc_operations(&mut global.num_operations, statements.position()) - { + if let Err(err) = self.track_operation(global, statements.position()) { loop_result = Err(err); break; } diff --git a/src/func/builtin.rs b/src/func/builtin.rs index 075706fe..6b16366f 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -298,7 +298,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option< ($x:ty, $xx:ident, $y:ty, $yy:ident) => { if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) { #[cfg(not(feature = "unchecked"))] - use crate::packages::arithmetic::decimal_functions::*; + use crate::packages::arithmetic::decimal_functions::builtin::*; #[cfg(not(feature = "unchecked"))] match op { @@ -697,7 +697,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt ($x:ident, $xx:ident, $y:ty, $yy:ident) => { if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) { #[cfg(not(feature = "unchecked"))] - use crate::packages::arithmetic::decimal_functions::*; + use crate::packages::arithmetic::decimal_functions::builtin::*; #[cfg(not(feature = "unchecked"))] return match op { diff --git a/src/func/call.rs b/src/func/call.rs index ea6349fe..c093c237 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -358,8 +358,7 @@ impl Engine { pos: Position, level: usize, ) -> RhaiResultOf<(Dynamic, bool)> { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, pos)?; + self.track_operation(global, pos)?; let parent_source = global.source.clone(); let op_assign = if is_op_assign { @@ -1232,8 +1231,7 @@ impl Engine { target = target.into_owned(); } - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, _pos)?; + self.track_operation(global, _pos)?; #[cfg(not(feature = "no_closure"))] let target_is_shared = target.is_shared(); @@ -1312,8 +1310,7 @@ impl Engine { let (target, _pos) = self.search_scope_only(scope, global, lib, this_ptr, first_arg, level)?; - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, _pos)?; + self.track_operation(global, _pos)?; #[cfg(not(feature = "no_closure"))] let target_is_shared = target.is_shared(); @@ -1350,9 +1347,7 @@ impl Engine { let mut func = match module.get_qualified_fn(hash) { // Then search native Rust functions None => { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, pos)?; - + self.track_operation(global, pos)?; let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id())); let hash_qualified_fn = combine_hashes(hash, hash_params); @@ -1384,8 +1379,7 @@ impl Engine { })); let hash_qualified_fn = combine_hashes(hash, hash_params); - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, pos)?; + self.track_operation(global, pos)?; if let Some(f) = module.get_qualified_fn(hash_qualified_fn) { func = Some(f); @@ -1461,8 +1455,7 @@ impl Engine { _pos: Position, level: usize, ) -> RhaiResult { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, _pos)?; + self.track_operation(global, _pos)?; let script = script.trim(); diff --git a/src/func/script.rs b/src/func/script.rs index 6d016cc5..c387b3dc 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -63,8 +63,7 @@ impl Engine { assert!(fn_def.params.len() == args.len()); - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, pos)?; + self.track_operation(global, pos)?; // Check for stack overflow if level > self.max_call_levels() { diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index 2cba468e..3dafc1ae 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -488,39 +488,29 @@ mod f64_functions { #[cfg(feature = "decimal")] #[export_module] pub mod decimal_functions { - use num_traits::Pow; - use rust_decimal::{prelude::Zero, Decimal, MathematicalOps}; + use rust_decimal::{prelude::Zero, Decimal}; - #[rhai_fn(skip, return_raw)] - pub fn add(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[cfg(not(feature = "unchecked"))] + pub mod builtin { + use rust_decimal::MathematicalOps; + + #[rhai_fn(return_raw)] + pub fn add(x: Decimal, y: Decimal) -> RhaiResultOf { x.checked_add(y) .ok_or_else(|| make_err(format!("Addition overflow: {x} + {y}"))) - } else { - Ok(x + y) } - } - #[rhai_fn(skip, return_raw)] - pub fn subtract(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[rhai_fn(return_raw)] + pub fn subtract(x: Decimal, y: Decimal) -> RhaiResultOf { x.checked_sub(y) .ok_or_else(|| make_err(format!("Subtraction overflow: {x} - {y}"))) - } else { - Ok(x - y) } - } - #[rhai_fn(skip, return_raw)] - pub fn multiply(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[rhai_fn(return_raw)] + pub fn multiply(x: Decimal, y: Decimal) -> RhaiResultOf { x.checked_mul(y) .ok_or_else(|| make_err(format!("Multiplication overflow: {x} * {y}"))) - } else { - Ok(x * y) } - } - #[rhai_fn(skip, return_raw)] - pub fn divide(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[rhai_fn(return_raw)] + pub fn divide(x: Decimal, y: Decimal) -> RhaiResultOf { // Detect division by zero if y == Decimal::zero() { Err(make_err(format!("Division by zero: {x} / {y}"))) @@ -528,26 +518,16 @@ pub mod decimal_functions { x.checked_div(y) .ok_or_else(|| make_err(format!("Division overflow: {x} / {y}"))) } - } else { - Ok(x / y) } - } - #[rhai_fn(skip, return_raw)] - pub fn modulo(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[rhai_fn(return_raw)] + pub fn modulo(x: Decimal, y: Decimal) -> RhaiResultOf { x.checked_rem(y) .ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {x} % {y}"))) - } else { - Ok(x % y) } - } - #[rhai_fn(skip, return_raw)] - pub fn power(x: Decimal, y: Decimal) -> RhaiResultOf { - if cfg!(not(feature = "unchecked")) { + #[rhai_fn(return_raw)] + pub fn power(x: Decimal, y: Decimal) -> RhaiResultOf { x.checked_powd(y) .ok_or_else(|| make_err(format!("Exponential overflow: {x} ** {y}"))) - } else { - Ok(x.pow(y)) } } #[rhai_fn(name = "-")] diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 72e2347e..7e639275 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -236,9 +236,8 @@ pub mod array_functions { } let check_sizes = match item.0 { - crate::types::dynamic::Union::Array(..) | crate::types::dynamic::Union::Str(..) => { - true - } + crate::types::dynamic::Union::Str(..) => true, + crate::types::dynamic::Union::Array(..) => true, #[cfg(not(feature = "no_object"))] crate::types::dynamic::Union::Map(..) => true, _ => false,