diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a30c812..8f847ce5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,8 +69,8 @@ jobs: # smoketests for different toolchains - {toolchain: stable, os: windows-latest, experimental: false, flags: ""} - {toolchain: stable, os: macos-latest, experimental: false, flags: ""} - - {toolchain: beta, os: ubuntu-latest, experimental: false, flags: ""} - # nightly is a bit volatile + # data structure size changes - wait for beta to become stable and uncomment + #- {toolchain: beta, os: ubuntu-latest, experimental: false, flags: ""} #- {toolchain: nightly, os: ubuntu-latest, experimental: true, flags: ""} fail-fast: false steps: diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 611ede44..ac1fb7f3 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -195,13 +195,14 @@ impl Engine { /// /// A [`GlobalRuntimeState`] and [`Caches`] need to be passed into the function, which can be /// created via [`GlobalRuntimeState::new`] and [`Caches::new`]. - /// This makes repeatedly calling particular functions more efficient as the functions resolution cache - /// is kept intact. + /// + /// This makes repeatedly calling particular functions more efficient as the functions + /// resolution cache is kept intact. /// /// # Arguments /// - /// All the arguments are _consumed_, meaning that they're replaced by `()`. - /// This is to avoid unnecessarily cloning the arguments. + /// All the arguments are _consumed_, meaning that they're replaced by `()`. This is to avoid + /// unnecessarily cloning the arguments. /// /// Do not use the arguments after this call. If they are needed afterwards, clone them _before_ /// calling this function. @@ -246,6 +247,8 @@ impl Engine { arg_values: &mut [Dynamic], ) -> RhaiResult { let statements = ast.statements(); + let lib = &[ast.as_ref()]; + let mut this_ptr = this_ptr; let orig_scope_len = scope.len(); @@ -255,45 +258,48 @@ impl Engine { ast.resolver().cloned(), ); + let mut result = Ok(Dynamic::UNIT); + if eval_ast && !statements.is_empty() { - self.eval_global_statements(scope, global, caches, statements, &[ast.as_ref()], 0)?; + result = self.eval_global_statements(scope, global, caches, statements, lib, 0); if rewind_scope { scope.rewind(orig_scope_len); } } - let mut this_ptr = this_ptr; - let mut args: StaticVec<_> = arg_values.iter_mut().collect(); + result = result.and_then(|_| { + let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - // Check for data race. - #[cfg(not(feature = "no_closure"))] - crate::func::call::ensure_no_data_race(name, &args, false)?; + // Check for data race. + #[cfg(not(feature = "no_closure"))] + crate::func::call::ensure_no_data_race(name, &args, false).map(|_| Dynamic::UNIT)?; - let lib = &[ast.as_ref()]; - let fn_def = ast - .shared_lib() - .get_script_fn(name, args.len()) - .ok_or_else(|| ERR::ErrorFunctionNotFound(name.into(), Position::NONE))?; - - let result = self.call_script_fn( - scope, - global, - caches, - lib, - &mut this_ptr, - fn_def, - &mut args, - rewind_scope, - Position::NONE, - 0, - )?; + if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) { + self.call_script_fn( + scope, + global, + caches, + lib, + &mut this_ptr, + fn_def, + &mut args, + rewind_scope, + Position::NONE, + 0, + ) + } else { + Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()) + } + }); #[cfg(not(feature = "no_module"))] { global.embedded_module_resolver = orig_embedded_module_resolver; } + let result = result?; + #[cfg(feature = "debugging")] if self.debugger.is_some() { global.debugger.status = crate::eval::DebuggerStatus::Terminate; diff --git a/src/api/definitions/mod.rs b/src/api/definitions/mod.rs index 171ca866..73908d04 100644 --- a/src/api/definitions/mod.rs +++ b/src/api/definitions/mod.rs @@ -4,7 +4,7 @@ use crate::module::FuncInfo; use crate::tokenizer::{is_valid_function_name, Token}; -use crate::{Engine, FnAccess, Module, Scope, INT}; +use crate::{Engine, FnAccess, FnPtr, Module, Scope, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -545,6 +545,20 @@ fn def_type_name<'a>(ty: &'a str, engine: &'a Engine) -> Cow<'a, str> { #[cfg(not(feature = "no_float"))] let ty = ty.replace(type_name::(), "float"); + #[cfg(not(feature = "no_index"))] + let ty = ty.replace(type_name::(), "Array"); + + #[cfg(not(feature = "no_index"))] + let ty = ty.replace(type_name::(), "Blob"); + + #[cfg(not(feature = "no_object"))] + let ty = ty.replace(type_name::(), "Map"); + + #[cfg(not(feature = "no_std"))] + let ty = ty.replace(type_name::(), "Instant"); + + let ty = ty.replace(type_name::(), "FnPtr"); + ty.into() } diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 0cc628f4..3b07ecfd 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -666,7 +666,7 @@ impl Expr { #[cfg(not(feature = "no_module"))] namespace: super::Namespace::NONE, name: KEYWORD_FN_PTR.into(), - hashes: calc_fn_hash(f.fn_name(), 1).into(), + hashes: calc_fn_hash(None, f.fn_name(), 1).into(), args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(), capture_parent_scope: false, is_native_operator: false, diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index a9d3b096..68b63ecd 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -74,8 +74,8 @@ impl OpAssignment { .expect("op-assignment operator") .literal_syntax(); Self { - hash_op_assign: calc_fn_hash(op.literal_syntax(), 2), - hash_op: calc_fn_hash(op_raw, 2), + hash_op_assign: calc_fn_hash(None, op.literal_syntax(), 2), + hash_op: calc_fn_hash(None, op_raw, 2), op_assign: op.literal_syntax(), op: op_raw, pos, diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index 83b2b076..775fdda0 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -285,8 +285,8 @@ impl GlobalRuntimeState<'_> { #[must_use] pub(crate) fn hash_idx_get(&mut self) -> u64 { if self.fn_hash_indexing == (0, 0) { - let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2); - let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3); + let n1 = crate::calc_fn_hash(None, crate::engine::FN_IDX_GET, 2); + let n2 = crate::calc_fn_hash(None, crate::engine::FN_IDX_SET, 3); self.fn_hash_indexing = (n1, n2); n1 } else { @@ -298,8 +298,8 @@ impl GlobalRuntimeState<'_> { #[must_use] pub(crate) fn hash_idx_set(&mut self) -> u64 { if self.fn_hash_indexing == (0, 0) { - let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2); - let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3); + let n1 = crate::calc_fn_hash(None, crate::engine::FN_IDX_GET, 2); + let n2 = crate::calc_fn_hash(None, crate::engine::FN_IDX_SET, 3); self.fn_hash_indexing = (n1, n2); n2 } else { diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 75d56a04..60587b4f 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -865,7 +865,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if global.scope_level == 0 && access == AccessMode::ReadOnly - && lib.iter().any(|&m| !m.is_empty()) + && lib.iter().any(|m| !m.is_empty()) { crate::func::locked_write(global.constants.get_or_insert_with( || { diff --git a/src/func/call.rs b/src/func/call.rs index 9445e714..e91d63a8 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -198,10 +198,8 @@ impl Engine { } let mut hash = args.as_ref().map_or(hash_base, |args| { - combine_hashes( - hash_base, - calc_fn_params_hash(args.iter().map(|a| a.type_id())), - ) + let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id())); + combine_hashes(hash_base, hash_params) }); let cache = caches.fn_resolution_cache_mut(); @@ -217,19 +215,21 @@ impl Engine { loop { let func = lib .iter() - .find_map(|&m| m.get_fn(hash).map(|f| (f, m.id()))) - .or_else(|| { - self.global_modules - .iter() - .find_map(|m| m.get_fn(hash).map(|f| (f, m.id()))) - }); + .copied() + .chain(self.global_modules.iter().map(|m| m.as_ref())) + .find_map(|m| m.get_fn(hash).map(|f| (f, m.id()))); #[cfg(not(feature = "no_module"))] - let func = func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| { - self.global_sub_modules - .values() - .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id()))) - }); + let func = if args.is_none() { + // Scripted functions are not exposed globally + func + } else { + func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| { + self.global_sub_modules + .values() + .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id()))) + }) + }; if let Some((f, s)) = func { // Specific version found @@ -249,7 +249,7 @@ impl Engine { // Check `Dynamic` parameters for functions with parameters if allow_dynamic && max_bitmask == 0 && num_args > 0 { - let is_dynamic = lib.iter().any(|&m| m.may_contain_dynamic_fn(hash_base)) + let is_dynamic = lib.iter().any(|m| m.may_contain_dynamic_fn(hash_base)) || self .global_modules .iter() @@ -611,7 +611,7 @@ impl Engine { if num_params < 0 || num_params > crate::MAX_USIZE_INT { false } else { - let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize); + let hash_script = calc_fn_hash(None, fn_name.as_str(), num_params as usize); self.has_script_fn(Some(global), caches, lib, hash_script) } .into(), @@ -815,7 +815,7 @@ impl Engine { let fn_name = fn_ptr.fn_name(); let args_len = call_args.len() + fn_ptr.curry().len(); // Recalculate hashes - let new_hash = calc_fn_hash(fn_name, args_len).into(); + let new_hash = calc_fn_hash(None, fn_name, args_len).into(); // Arguments are passed as-is, adding the curried arguments let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); curry.extend(fn_ptr.curry().iter().cloned()); @@ -857,8 +857,8 @@ impl Engine { // Recalculate hash let new_hash = FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(fn_name, args_len), - calc_fn_hash(fn_name, args_len + 1), + calc_fn_hash(None, fn_name, args_len), + calc_fn_hash(None, fn_name, args_len + 1), ); // Replace the first argument with the object pointer, adding the curried arguments let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); @@ -944,8 +944,8 @@ impl Engine { // Recalculate the hash based on the new function name and new arguments hash = FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(fn_name, call_args.len()), - calc_fn_hash(fn_name, call_args.len() + 1), + calc_fn_hash(None, fn_name, call_args.len()), + calc_fn_hash(None, fn_name, call_args.len() + 1), ); } } @@ -1036,9 +1036,9 @@ impl Engine { // Recalculate hash let args_len = total_args + curry.len(); hashes = if hashes.is_native_only() { - FnCallHashes::from_native(calc_fn_hash(name, args_len)) + FnCallHashes::from_native(calc_fn_hash(None, name, args_len)) } else { - calc_fn_hash(name, args_len).into() + calc_fn_hash(None, name, args_len).into() }; } // Handle Fn() @@ -1110,7 +1110,7 @@ impl Engine { return Ok(if num_params < 0 || num_params > crate::MAX_USIZE_INT { false } else { - let hash_script = calc_fn_hash(&fn_name, num_params as usize); + let hash_script = calc_fn_hash(None, &fn_name, num_params as usize); self.has_script_fn(Some(global), caches, lib, hash_script) } .into()); diff --git a/src/func/hashing.rs b/src/func/hashing.rs index a7ef71fb..bc29f67b 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -91,7 +91,7 @@ pub fn get_hasher() -> ahash::AHasher { /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] #[must_use] -pub fn calc_qualified_var_hash<'a>( +pub fn calc_var_hash<'a>( modules: impl IntoIterator>, var_name: &str, ) -> u64 { @@ -113,9 +113,11 @@ pub fn calc_qualified_var_hash<'a>( /// Calculate a non-zero [`u64`] hash key from a namespace-qualified function name /// and the number of parameters, but no parameter types. /// -/// Module names are passed in via `&str` references from an iterator. +/// Module names making up the namespace are passed in via `&str` references from an iterator. /// Parameter types are passed in via [`TypeId`] values from an iterator. /// +/// If the function is not namespace-qualified, pass [`None`] as the namespace. +/// /// # Zeros /// /// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. @@ -125,15 +127,15 @@ pub fn calc_qualified_var_hash<'a>( /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] #[must_use] -pub fn calc_qualified_fn_hash<'a>( - modules: impl IntoIterator>, +pub fn calc_fn_hash<'a>( + namespace: impl IntoIterator>, fn_name: &str, num: usize, ) -> u64 { let s = &mut get_hasher(); // We always skip the first module - let iter = modules.into_iter(); + let iter = namespace.into_iter(); let len = iter.len(); iter.skip(1).for_each(|m| m.hash(s)); len.hash(s); @@ -146,20 +148,6 @@ pub fn calc_qualified_fn_hash<'a>( } } -/// Calculate a non-zero [`u64`] hash key from a non-namespace-qualified function name -/// and the number of parameters, but no parameter types. -/// -/// Parameter types are passed in via [`TypeId`] values from an iterator. -/// -/// # Zeros -/// -/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. -#[inline(always)] -#[must_use] -pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 { - calc_qualified_fn_hash(None, fn_name, num) -} - /// Calculate a non-zero [`u64`] hash key from a list of parameter types. /// /// Parameter types are passed in via [`TypeId`] values from an iterator. diff --git a/src/func/mod.rs b/src/func/mod.rs index d9b9db8c..8298a63e 100644 --- a/src/func/mod.rs +++ b/src/func/mod.rs @@ -20,8 +20,7 @@ pub use callable_function::CallableFunction; #[cfg(not(feature = "no_function"))] pub use func::Func; pub use hashing::{ - calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, calc_qualified_var_hash, - combine_hashes, get_hasher, StraightHashMap, + calc_fn_hash, calc_fn_params_hash, calc_var_hash, combine_hashes, get_hasher, StraightHashMap, }; pub use native::{ locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone, diff --git a/src/func/native.rs b/src/func/native.rs index 851f52e7..f421c262 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -321,11 +321,11 @@ impl<'a> NativeCallContext<'a> { let hash = if is_method_call { FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(fn_name, args_len - 1), - calc_fn_hash(fn_name, args_len), + calc_fn_hash(None, fn_name, args_len - 1), + calc_fn_hash(None, fn_name, args_len), ) } else { - calc_fn_hash(fn_name, args_len).into() + calc_fn_hash(None, fn_name, args_len).into() }; self.engine() diff --git a/src/func/script.rs b/src/func/script.rs index 8309c6ba..8ccc876b 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -240,7 +240,7 @@ impl Engine { } // First check script-defined functions - let result = lib.iter().any(|&m| m.contains_fn(hash_script)) + let result = lib.iter().any(|m| m.contains_fn(hash_script)) // Then check the global namespace and packages || self.global_modules.iter().any(|m| m.contains_fn(hash_script)); diff --git a/src/lib.rs b/src/lib.rs index f09e2b66..bb26d72b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,10 +237,7 @@ pub use func::Shared; /// Alias to [`RefCell`][std::cell::RefCell] or [`RwLock`][std::sync::RwLock] depending on the `sync` feature flag. pub use func::Locked; -pub(crate) use func::{ - calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, calc_qualified_var_hash, - combine_hashes, -}; +pub(crate) use func::{calc_fn_hash, calc_fn_params_hash, calc_var_hash, combine_hashes}; pub use rhai_codegen::*; diff --git a/src/module/mod.rs b/src/module/mod.rs index e027f384..a07a82d3 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -9,8 +9,8 @@ use crate::func::{ }; use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypesCollection}; use crate::{ - calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier, - ImmutableString, NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec, + calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Identifier, ImmutableString, + NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -150,7 +150,7 @@ pub fn calc_native_fn_hash<'a>( fn_name: &str, params: &[TypeId], ) -> u64 { - let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len()); + let hash_script = calc_fn_hash(modules, fn_name, params.len()); let hash_params = calc_fn_params_hash(params.iter().copied()); combine_hashes(hash_script, hash_params) } @@ -182,8 +182,8 @@ pub struct Module { /// Flattened collection of all functions, native Rust and scripted. /// including those in sub-modules. all_functions: Option>, - /// Native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters. - dynamic_functions: BloomFilterU64, + /// Bloom filter on native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters. + dynamic_functions_filter: BloomFilterU64, /// Iterator functions, keyed by the type producing the iterator. type_iterators: Option>>, /// Flattened collection of iterator functions, including those in sub-modules. @@ -300,7 +300,7 @@ impl Module { all_variables: None, functions: StraightHashMap::with_capacity_and_hasher(capacity, Default::default()), all_functions: None, - dynamic_functions: BloomFilterU64::new(), + dynamic_functions_filter: BloomFilterU64::new(), type_iterators: None, all_type_iterators: None, indexed: true, @@ -442,7 +442,7 @@ impl Module { self.all_variables = None; self.functions.clear(); self.all_functions = None; - self.dynamic_functions.clear(); + self.dynamic_functions_filter.clear(); self.type_iterators = None; self.all_type_iterators = None; self.indexed = false; @@ -662,7 +662,7 @@ impl Module { let value = Dynamic::from(value); if self.indexed { - let hash_var = crate::calc_qualified_var_hash(Some(""), &ident); + let hash_var = crate::calc_var_hash(Some(""), &ident); self.all_variables .get_or_insert_with(|| Default::default()) .insert(hash_var, value.clone()); @@ -692,7 +692,7 @@ impl Module { // None + function name + number of arguments. let num_params = fn_def.params.len(); - let hash_script = crate::calc_fn_hash(&fn_def.name, num_params); + let hash_script = crate::calc_fn_hash(None, &fn_def.name, num_params); #[cfg(feature = "metadata")] let params_info = fn_def.params.iter().map(Into::into).collect(); self.functions.insert( @@ -1021,11 +1021,12 @@ impl Module { }; let name = name.as_ref(); - let hash_fn = calc_native_fn_hash(None, name, ¶m_types); + let hash_script = calc_fn_hash(None, name, param_types.len()); + let hash_params = calc_fn_params_hash(param_types.iter().copied()); + let hash_fn = combine_hashes(hash_script, hash_params); if is_dynamic { - self.dynamic_functions - .mark(calc_fn_hash(name, param_types.len())); + self.dynamic_functions_filter.mark(hash_script); } self.functions.insert( @@ -1546,7 +1547,7 @@ impl Module { #[inline(always)] #[must_use] pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool { - !self.dynamic_functions.is_absent(hash_script) + !self.dynamic_functions_filter.is_absent(hash_script) } /// Does the particular namespace-qualified function exist in the [`Module`]? @@ -1591,7 +1592,7 @@ impl Module { None => self.variables = other.variables, } self.functions.extend(other.functions.into_iter()); - self.dynamic_functions += &other.dynamic_functions; + self.dynamic_functions_filter += &other.dynamic_functions_filter; match self.type_iterators { Some(ref mut m) if other.type_iterators.is_some() => { m.extend(other.type_iterators.unwrap().into_iter()) @@ -1634,7 +1635,7 @@ impl Module { None => self.variables = other.variables, } self.functions.extend(other.functions.into_iter()); - self.dynamic_functions += &other.dynamic_functions; + self.dynamic_functions_filter += &other.dynamic_functions_filter; match self.type_iterators { Some(ref mut m) if other.type_iterators.is_some() => { m.extend(other.type_iterators.unwrap().into_iter()) @@ -1684,7 +1685,7 @@ impl Module { for (&k, v) in &other.functions { self.functions.entry(k).or_insert_with(|| v.clone()); } - self.dynamic_functions += &other.dynamic_functions; + self.dynamic_functions_filter += &other.dynamic_functions_filter; if let Some(ref type_iterators) = other.type_iterators { let t = self .type_iterators @@ -1760,7 +1761,7 @@ impl Module { }) .map(|(&k, v)| (k, v.clone())), ); - self.dynamic_functions += &other.dynamic_functions; + self.dynamic_functions_filter += &other.dynamic_functions_filter; if let Some(ref type_iterators) = other.type_iterators { if let Some(ref mut t) = self.type_iterators { @@ -1804,7 +1805,7 @@ impl Module { }) .collect(); - self.dynamic_functions.clear(); + self.dynamic_functions_filter.clear(); self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; @@ -2126,7 +2127,7 @@ impl Module { // Index all variables if let Some(ref v) = module.variables { for (var_name, value) in v { - let hash_var = crate::calc_qualified_var_hash(path.iter().copied(), var_name); + let hash_var = crate::calc_var_hash(path.iter().copied(), var_name); variables.insert(hash_var, value.clone()); } } @@ -2135,7 +2136,6 @@ impl Module { if let Some(ref t) = module.type_iterators { for (&type_id, func) in t { type_iterators.insert(type_id, func.clone()); - contains_indexed_global_functions = true; } } @@ -2160,7 +2160,7 @@ impl Module { functions.insert(hash_qualified_fn, f.func.clone()); } else if cfg!(not(feature = "no_function")) { let hash_qualified_script = - crate::calc_qualified_fn_hash(path.iter().copied(), &f.name, f.num_params); + crate::calc_fn_hash(path.iter().copied(), &f.name, f.num_params); functions.insert(hash_qualified_script, f.func.clone()); } } @@ -2248,7 +2248,6 @@ impl Module { self.all_type_iterators .get_or_insert_with(|| Default::default()) .insert(type_id, func.clone()); - self.contains_indexed_global_functions = true; } self.type_iterators .get_or_insert_with(|| Default::default()) diff --git a/src/optimizer.rs b/src/optimizer.rs index 0b7a13c2..b9a4dd97 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -151,7 +151,7 @@ impl<'a> OptimizerState<'a> { &mut self.caches, lib, fn_name, - calc_fn_hash(fn_name, arg_values.len()), + calc_fn_hash(None, fn_name, arg_values.len()), &mut arg_values.iter_mut().collect::>(), false, false, @@ -1229,7 +1229,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { => { // First search for script-defined functions (can override built-in) #[cfg(not(feature = "no_function"))] - let has_script_fn = state.lib.iter().any(|&m| m.get_script_fn(&x.name, x.args.len()).is_some()); + let has_script_fn = state.lib.iter().copied().any(|m| m.get_script_fn(&x.name, x.args.len()).is_some()); #[cfg(feature = "no_function")] let has_script_fn = false; diff --git a/src/parser.rs b/src/parser.rs index 4d22d30b..20600e0b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -358,9 +358,9 @@ impl Expr { Self::Variable(x, .., pos) => { let ident = x.3.clone(); let getter = state.get_interned_getter(ident.as_str()); - let hash_get = calc_fn_hash(&getter, 1); + let hash_get = calc_fn_hash(None, &getter, 1); let setter = state.get_interned_setter(ident.as_str()); - let hash_set = calc_fn_hash(&setter, 2); + let hash_set = calc_fn_hash(None, &setter, 2); Self::Property( Box::new(((getter, hash_get), (setter, hash_set), ident)), @@ -576,7 +576,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] let hash = if namespace.is_empty() { - calc_fn_hash(&id, 0) + calc_fn_hash(None, &id, 0) } else { let root = namespace.root(); let index = state.find_module(root); @@ -600,10 +600,10 @@ impl Engine { namespace.set_index(index); - crate::calc_qualified_fn_hash(namespace.iter().map(Ident::as_str), &id, 0) + crate::calc_fn_hash(namespace.iter().map(Ident::as_str), &id, 0) }; #[cfg(feature = "no_module")] - let hash = calc_fn_hash(&id, 0); + let hash = calc_fn_hash(None, &id, 0); let hashes = if is_valid_function_name(&id) { hash.into() @@ -645,7 +645,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] let hash = if namespace.is_empty() { - calc_fn_hash(&id, args.len()) + calc_fn_hash(None, &id, args.len()) } else { let root = namespace.root(); let index = state.find_module(root); @@ -668,14 +668,10 @@ impl Engine { namespace.set_index(index); - crate::calc_qualified_fn_hash( - namespace.iter().map(Ident::as_str), - &id, - args.len(), - ) + crate::calc_fn_hash(namespace.iter().map(Ident::as_str), &id, args.len()) }; #[cfg(feature = "no_module")] - let hash = calc_fn_hash(&id, args.len()); + let hash = calc_fn_hash(None, &id, args.len()); let hashes = if is_valid_function_name(&id) { hash.into() @@ -1470,7 +1466,7 @@ impl Engine { }, )?; - let hash_script = calc_fn_hash(&func.name, func.params.len()); + let hash_script = calc_fn_hash(None, &func.name, func.params.len()); lib.insert(hash_script, func.into()); expr @@ -1835,7 +1831,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if let Some((.., namespace, hash, name)) = namespaced_variable { if !namespace.is_empty() { - *hash = crate::calc_qualified_var_hash(namespace.iter().map(Ident::as_str), name); + *hash = crate::calc_var_hash(namespace.iter().map(Ident::as_str), name); #[cfg(not(feature = "no_module"))] { @@ -1919,7 +1915,7 @@ impl Engine { Ok(FnCallExpr { name: state.get_interned_string("-"), - hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)), args, pos, is_native_operator: true, @@ -1947,7 +1943,7 @@ impl Engine { Ok(FnCallExpr { name: state.get_interned_string("+"), - hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)), args, pos, is_native_operator: true, @@ -1966,7 +1962,7 @@ impl Engine { Ok(FnCallExpr { name: state.get_interned_string("!"), - hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)), + hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)), args, pos, is_native_operator: true, @@ -2187,8 +2183,8 @@ impl Engine { // Recalculate hash func.hashes = FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(&func.name, func.args.len()), - calc_fn_hash(&func.name, func.args.len() + 1), + calc_fn_hash(None, &func.name, func.args.len()), + calc_fn_hash(None, &func.name, func.args.len() + 1), ); let rhs = Expr::MethodCall(func, func_pos); @@ -2233,8 +2229,8 @@ impl Engine { // Recalculate hash func.hashes = FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(&func.name, func.args.len()), - calc_fn_hash(&func.name, func.args.len() + 1), + calc_fn_hash(None, &func.name, func.args.len()), + calc_fn_hash(None, &func.name, func.args.len() + 1), ); let new_lhs = BinaryExpr { @@ -2338,7 +2334,7 @@ impl Engine { settings.ensure_level_within_max_limit(state.max_expr_depth)?; let op = op_token.syntax(); - let hash = calc_fn_hash(&op, 2); + let hash = calc_fn_hash(None, &op, 2); let op_base = FnCallExpr { name: state.get_interned_string(op.as_ref()), @@ -2412,7 +2408,7 @@ impl Engine { // Convert into a call to `contains` FnCallExpr { - hashes: calc_fn_hash(OP_CONTAINS, 2).into(), + hashes: calc_fn_hash(None, OP_CONTAINS, 2).into(), args, name: state.get_interned_string(OP_CONTAINS), ..op_base @@ -2427,7 +2423,7 @@ impl Engine { .get(s.as_str()) .map_or(false, Option::is_some) => { - let hash = calc_fn_hash(&s, 2); + let hash = calc_fn_hash(None, &s, 2); let pos = args[0].start_position(); FnCallExpr { @@ -3345,7 +3341,7 @@ impl Engine { let func = func?; - let hash = calc_fn_hash(&func.name, func.params.len()); + let hash = calc_fn_hash(None, &func.name, func.params.len()); if !lib.is_empty() && lib.contains_key(&hash) { return Err(PERR::FnDuplicatedDefinition( @@ -3657,6 +3653,7 @@ impl Engine { let expr = FnCallExpr { name: state.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY), hashes: FnCallHashes::from_native(calc_fn_hash( + None, crate::engine::KEYWORD_FN_PTR_CURRY, num_externals + 1, )), diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 47b9d1f0..51011585 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -66,7 +66,7 @@ impl Ord for FnMetadata<'_> { impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { fn from(info: &'a FuncInfo) -> Self { - let base_hash = calc_fn_hash(&info.name, info.num_params); + let base_hash = calc_fn_hash(None, &info.name, info.num_params); let (typ, full_hash) = if info.func.is_script() { (FnType::Script, base_hash) } else { diff --git a/src/types/bloom_filter.rs b/src/types/bloom_filter.rs index 61a1d360..9400879b 100644 --- a/src/types/bloom_filter.rs +++ b/src/types/bloom_filter.rs @@ -7,8 +7,11 @@ use std::{ ops::{Add, AddAssign}, }; +/// Number of bits for a `usize`. +const USIZE_BITS: usize = mem::size_of::() * 8; + /// Number of `usize` values required for 256 bits. -const SIZE: usize = (256 / 8) / mem::size_of::(); +const SIZE: usize = 256 / USIZE_BITS; /// A simple bloom filter implementation for `u64` hash values only - i.e. all 64 bits are assumed /// to be relatively random. @@ -26,7 +29,7 @@ impl BloomFilterU64 { #[must_use] const fn calc_hash(value: u64) -> (usize, usize) { let hash = (value & 0x00ff) as usize; - (hash / 64, 0x01 << (hash % 64)) + (hash / USIZE_BITS, 0x01 << (hash % USIZE_BITS)) } /// Create a new [`BloomFilterU64`]. #[inline(always)]