diff --git a/src/engine.rs b/src/engine.rs index b0aa1400..dc645b3a 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -3,7 +3,7 @@ use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, Stmt, AST_OPTION_FLAGS::*}; use crate::custom_syntax::CustomSyntax; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; -use crate::fn_hash::{calc_fn_hash, get_hasher}; +use crate::fn_hash::get_hasher; use crate::fn_native::{ CallableFunction, IteratorFn, OnDebugCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback, @@ -682,6 +682,9 @@ pub struct EvalState { /// Embedded module resolver. #[cfg(not(feature = "no_module"))] pub embedded_module_resolver: Option>, + /// Function call hashes to FN_IDX_GET and FN_IDX_SET + #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] + fn_hash_indexing: (u64, u64), } impl EvalState { @@ -698,6 +701,8 @@ impl EvalState { #[cfg(not(feature = "no_module"))] embedded_module_resolver: None, fn_resolution_caches: StaticVec::new(), + #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] + fn_hash_indexing: (0, 0), } } /// Is the state currently at global (root) level? @@ -735,6 +740,32 @@ impl EvalState { .pop() .expect("at least one function resolution cache"); } + /// Get the pre-calculated index getter hash. + #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] + #[must_use] + pub fn fn_hash_idx_get(&mut self) -> u64 { + if self.fn_hash_indexing != (0, 0) { + self.fn_hash_indexing.0 + } else { + let n1 = crate::calc_fn_hash(FN_IDX_GET, 2); + let n2 = crate::calc_fn_hash(FN_IDX_SET, 3); + self.fn_hash_indexing = (n1, n2); + n1 + } + } + /// Get the pre-calculated index setter hash. + #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] + #[must_use] + pub fn fn_hash_idx_set(&mut self) -> u64 { + if self.fn_hash_indexing != (0, 0) { + self.fn_hash_indexing.1 + } else { + let n1 = crate::calc_fn_hash(FN_IDX_GET, 2); + let n2 = crate::calc_fn_hash(FN_IDX_SET, 3); + self.fn_hash_indexing = (n1, n2); + n2 + } + } } /// _(internals)_ A type containing all the limits imposed by the [`Engine`]. @@ -804,31 +835,6 @@ impl Default for Limits { } } -/// A type containing useful constants for the [`Engine`]. -#[derive(Debug)] -pub struct GlobalConstants { - /// An empty [`ImmutableString`] for cloning purposes. - pub(crate) empty_string: ImmutableString, - /// Function call hash to FN_IDX_GET - #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - pub(crate) fn_hash_idx_get: u64, - /// Function call hash to FN_IDX_SET - #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - pub(crate) fn_hash_idx_set: u64, -} - -impl Default for GlobalConstants { - fn default() -> Self { - Self { - empty_string: Default::default(), - #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - fn_hash_idx_get: calc_fn_hash(FN_IDX_GET, 2), - #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] - fn_hash_idx_set: calc_fn_hash(FN_IDX_SET, 3), - } - } -} - /// Context of a script evaluation process. #[derive(Debug)] pub struct EvalContext<'a, 'x, 'px, 'm, 's, 'b, 't, 'pt> { @@ -950,8 +956,8 @@ pub struct Engine { /// A map mapping type names to pretty-print names. pub(crate) type_names: BTreeMap>, - /// Useful constants - pub(crate) constants: GlobalConstants, + /// An empty [`ImmutableString`] for cloning purposes. + pub(crate) empty_string: ImmutableString, /// A set of symbols to disable. pub(crate) disabled_symbols: BTreeSet, @@ -1081,7 +1087,7 @@ impl Engine { module_resolver: None, type_names: Default::default(), - constants: Default::default(), + empty_string: Default::default(), disabled_symbols: Default::default(), custom_keywords: Default::default(), custom_syntax: Default::default(), @@ -1116,7 +1122,7 @@ impl Engine { #[inline(always)] #[must_use] pub fn const_empty_string(&self) -> ImmutableString { - self.constants.empty_string.clone() + self.empty_string.clone() } /// Search for a module within an imports stack. @@ -1328,8 +1334,7 @@ impl Engine { if let Some(mut new_val) = try_setter { // Try to call index setter if value is changed - let hash_set = - FnCallHashes::from_native(self.constants.fn_hash_idx_set); + let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set()); let args = &mut [target, &mut idx_val_for_setter, &mut new_val]; if let Err(err) = self.exec_fn_call( @@ -1376,8 +1381,7 @@ impl Engine { if let Some(mut new_val) = try_setter { // Try to call index setter - let hash_set = - FnCallHashes::from_native(self.constants.fn_hash_idx_set); + let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set()); let args = &mut [target, &mut idx_val_for_setter, &mut new_val]; self.exec_fn_call( @@ -1508,8 +1512,7 @@ impl Engine { // Try an indexer if property does not exist EvalAltResult::ErrorDotExpr(_, _) => { let args = &mut [target, &mut name.into(), &mut new_val]; - let hash_set = - FnCallHashes::from_native(self.constants.fn_hash_idx_set); + let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set()); let pos = Position::NONE; self.exec_fn_call( @@ -1668,7 +1671,7 @@ impl Engine { let args = &mut [target.as_mut(), &mut name.into(), val]; let hash_set = FnCallHashes::from_native( - self.constants.fn_hash_idx_set, + state.fn_hash_idx_set(), ); self.exec_fn_call( mods, state, lib, FN_IDX_SET, hash_set, args, @@ -2072,7 +2075,7 @@ impl Engine { _ if use_indexers => { let args = &mut [target, &mut idx]; - let hash_get = FnCallHashes::from_native(self.constants.fn_hash_idx_get); + let hash_get = FnCallHashes::from_native(state.fn_hash_idx_get()); let idx_pos = Position::NONE; self.exec_fn_call( @@ -3096,7 +3099,7 @@ impl Engine { // Concentrate all empty strings into one instance to save memory if let Dynamic(crate::dynamic::Union::Str(s, _, _)) = r { if s.is_empty() { - if !s.ptr_eq(&self.constants.empty_string) { + if !s.ptr_eq(&self.empty_string) { *s = self.const_empty_string(); } return result;