diff --git a/src/fn_hash.rs b/src/fn_hash.rs index c503daf5..887ebceb 100644 --- a/src/fn_hash.rs +++ b/src/fn_hash.rs @@ -52,6 +52,33 @@ pub fn get_hasher() -> ahash::AHasher { Default::default() } +/// Calculate a [`u64`] hash key from a namespace-qualified variable name. +/// +/// Module names are passed in via `&str` references from an iterator. +/// Parameter types are passed in via [`TypeId`] values from an iterator. +/// +/// # Note +/// +/// 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>( + modules: impl Iterator, + var_name: impl AsRef, +) -> u64 { + let s = &mut get_hasher(); + + // We always skip the first module + let mut len = 0; + modules + .inspect(|_| len += 1) + .skip(1) + .for_each(|m| m.hash(s)); + len.hash(s); + var_name.as_ref().hash(s); + s.finish() +} + /// Calculate a [`u64`] hash key from a namespace-qualified function name /// and the number of parameters, but no parameter types. /// diff --git a/src/lib.rs b/src/lib.rs index 9bd8e204..6d1a9aae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -172,7 +172,8 @@ pub use fn_native::Shared; use fn_native::Locked; pub(crate) use fn_hash::{ - calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, + calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, calc_qualified_var_hash, + combine_hashes, }; pub use rhai_codegen::*; diff --git a/src/module/mod.rs b/src/module/mod.rs index dbb5535b..19d674e5 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -447,7 +447,7 @@ impl Module { let value = Dynamic::from(value); if self.indexed { - let hash_var = crate::calc_qualified_fn_hash(once(""), &ident, 0); + let hash_var = crate::calc_qualified_var_hash(once(""), &ident); self.all_variables.insert(hash_var, value.clone()); } self.variables.insert(ident, value); @@ -1529,7 +1529,7 @@ impl Module { // Index all variables module.variables.iter().for_each(|(var_name, value)| { - let hash_var = crate::calc_qualified_fn_hash(path.iter().map(|&v| v), var_name, 0); + let hash_var = crate::calc_qualified_var_hash(path.iter().map(|&v| v), var_name); variables.insert(hash_var, value.clone()); }); diff --git a/src/parse.rs b/src/parse.rs index 0de53e8c..33380e50 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -10,16 +10,15 @@ use crate::custom_syntax::{ }; use crate::dynamic::{AccessMode, Union}; use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS}; +use crate::fn_hash::get_hasher; use crate::module::NamespaceRef; use crate::optimize::{optimize_into_ast, OptimizationLevel}; - -use crate::fn_hash::get_hasher; use crate::token::{ is_keyword_function, is_valid_identifier, Token, TokenStream, TokenizerControl, }; use crate::{ - calc_fn_hash, calc_qualified_fn_hash, Dynamic, Engine, Identifier, LexError, ParseError, - ParseErrorType, Position, Scope, Shared, StaticVec, AST, + calc_fn_hash, calc_qualified_fn_hash, calc_qualified_var_hash, Dynamic, Engine, Identifier, + LexError, ParseError, ParseErrorType, Position, Scope, Shared, StaticVec, AST, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -1354,7 +1353,7 @@ fn parse_primary( } .map(|x| match x { (_, Some((namespace, hash)), name) => { - *hash = calc_qualified_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0); + *hash = calc_qualified_var_hash(namespace.iter().map(|v| v.name.as_str()), name); #[cfg(not(feature = "no_module"))] namespace.set_index(state.find_module(&namespace[0].name));