diff --git a/src/ast.rs b/src/ast.rs index 33b784d0..c4778bef 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,7 +1,7 @@ //! Module defining the AST (abstract syntax tree). use crate::calc_fn_hash; -use crate::func::hashing::DEFAULT_HASH; +use crate::func::hashing::ALT_ZERO_HASH; use crate::module::NamespaceRef; use crate::tokenizer::Token; use crate::types::dynamic::Union; @@ -1800,7 +1800,7 @@ impl OpAssignment<'_> { /// to possible function overloading for different parameter types. #[derive(Clone, Copy, Eq, PartialEq, Hash, Default)] pub struct FnCallHashes { - /// Pre-calculated hash for a script-defined function ([`None`] if native functions only). + /// Pre-calculated hash for a script-defined function (zero if native functions only). #[cfg(not(feature = "no_function"))] pub script: u64, /// Pre-calculated hash for a native Rust function with no parameter types. @@ -1825,7 +1825,7 @@ impl fmt::Debug for FnCallHashes { impl From for FnCallHashes { #[inline(always)] fn from(hash: u64) -> Self { - let hash = if hash == 0 { DEFAULT_HASH } else { hash }; + let hash = if hash == 0 { ALT_ZERO_HASH } else { hash }; Self { #[cfg(not(feature = "no_function"))] @@ -1843,7 +1843,7 @@ impl FnCallHashes { Self { #[cfg(not(feature = "no_function"))] script: 0, - native: if hash == 0 { DEFAULT_HASH } else { hash }, + native: if hash == 0 { ALT_ZERO_HASH } else { hash }, } } /// Create a [`FnCallHashes`] with both native Rust and script function hashes. @@ -1852,8 +1852,8 @@ impl FnCallHashes { pub const fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self { Self { #[cfg(not(feature = "no_function"))] - script: if script == 0 { DEFAULT_HASH } else { script }, - native: if native == 0 { DEFAULT_HASH } else { native }, + script: if script == 0 { ALT_ZERO_HASH } else { script }, + native: if native == 0 { ALT_ZERO_HASH } else { native }, } } /// Is this [`FnCallHashes`] native Rust only? diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 0159e84e..38a8b636 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -8,13 +8,24 @@ use std::{ iter::empty, }; -pub const DEFAULT_HASH: u64 = 42; +/// Dummy hash value to map zeros to. This value can be anything. +/// +/// # Notes +/// +/// Hashes are `u64`, and they can be zero (although extremely unlikely). +/// It is possible to hijack the zero value to indicate non-existence, +/// like [`None`] in [`Option`]. +/// +/// When a hash is calculated to be zero, it gets mapped to this alternate hash value. +/// This has the effect of releasing the zero value at the expense of causing the probability of +/// this value to double, which has minor impacts. +pub const ALT_ZERO_HASH: u64 = 42; /// A hasher that only takes one single [`u64`] and returns it as a non-zero hash key. /// /// # Zeros /// -/// If the value is zero, then it is mapped to `DEFAULT_HASH`. +/// If the value is zero, it is mapped to `ALT_ZERO_HASH`. /// /// # Panics /// @@ -37,7 +48,7 @@ impl Hasher for StraightHasher { self.0 = u64::from_ne_bytes(key); if self.0 == 0 { - self.0 = DEFAULT_HASH + self.0 = ALT_ZERO_HASH } } } @@ -51,7 +62,7 @@ impl BuildHasher for StraightHasherBuilder { #[inline(always)] fn build_hasher(&self) -> Self::Hasher { - StraightHasher(DEFAULT_HASH) + StraightHasher(ALT_ZERO_HASH) } } @@ -92,7 +103,7 @@ pub fn calc_qualified_var_hash<'a>( var_name.as_ref().hash(s); match s.finish() { - 0 => DEFAULT_HASH, + 0 => ALT_ZERO_HASH, r => r, } } @@ -130,7 +141,7 @@ pub fn calc_qualified_fn_hash( num.hash(s); match s.finish() { - 0 => DEFAULT_HASH, + 0 => ALT_ZERO_HASH, r => r, } } @@ -165,7 +176,7 @@ pub fn calc_fn_params_hash(params: impl Iterator) -> u64 { len.hash(s); match s.finish() { - 0 => DEFAULT_HASH, + 0 => ALT_ZERO_HASH, r => r, } } @@ -179,7 +190,7 @@ pub fn calc_fn_params_hash(params: impl Iterator) -> u64 { #[must_use] pub const fn combine_hashes(a: u64, b: u64) -> u64 { match a ^ b { - 0 => DEFAULT_HASH, + 0 => ALT_ZERO_HASH, r => r, } } diff --git a/src/module/mod.rs b/src/module/mod.rs index 841c5d2b..7cc982d6 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -96,8 +96,7 @@ impl FuncInfo { } } -/// _(internals)_ Calculate a [`u64`] hash key from a namespace-qualified function name and -/// parameter types. +/// _(internals)_ Calculate a non-zero [`u64`] hash key from a namespace-qualified function name and parameter types. /// Exported under the `internals` feature only. /// /// Module names are passed in via `&str` references from an iterator. @@ -667,7 +666,7 @@ impl Module { type_id } - /// Set a Rust function into the [`Module`], returning a hash key. + /// Set a Rust function into the [`Module`], returning a non-zero hash key. /// /// If there is an existing Rust function of the same hash, it is replaced. /// @@ -729,7 +728,7 @@ impl Module { /// Set a Rust function taking a reference to the scripting [`Engine`][crate::Engine], /// the current set of functions, plus a list of mutable [`Dynamic`] references - /// into the [`Module`], returning a hash key. + /// into the [`Module`], returning a non-zero hash key. /// /// Use this to register a built-in function which must reference settings on the scripting /// [`Engine`][crate::Engine] (e.g. to prevent growing an array beyond the allowed maximum size), @@ -822,7 +821,7 @@ impl Module { ) } - /// Set a Rust function into the [`Module`], returning a hash key. + /// Set a Rust function into the [`Module`], returning a non-zero hash key. /// /// If there is a similar existing Rust function, it is replaced. /// @@ -861,7 +860,7 @@ impl Module { ) } - /// Set a Rust getter function taking one mutable parameter, returning a hash key. + /// Set a Rust getter function taking one mutable parameter, returning a non-zero hash key. /// This function is automatically exposed to the global namespace. /// /// If there is a similar existing Rust getter function, it is replaced. @@ -898,7 +897,7 @@ impl Module { } /// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`], - /// returning a hash key. + /// returning a non-zero hash key. /// This function is automatically exposed to the global namespace. /// /// If there is a similar existing setter Rust function, it is replaced. @@ -939,7 +938,7 @@ impl Module { } /// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`], - /// returning a hash key. + /// returning a non-zero hash key. /// This function is automatically exposed to the global namespace. /// /// If there is a similar existing setter Rust function, it is replaced. @@ -1000,7 +999,7 @@ impl Module { } /// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`], - /// returning a hash key. + /// returning a non-zero hash key. /// This function is automatically exposed to the global namespace. /// /// If there is a similar existing Rust function, it is replaced. @@ -1060,7 +1059,7 @@ impl Module { ) } - /// Set a pair of Rust index getter and setter functions, returning both hash keys. + /// Set a pair of Rust index getter and setter functions, returning both non-zero hash keys. /// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and /// [`set_indexer_set_fn`][Module::set_indexer_set_fn]. ///