JenkHash 0.3.0

Bob Jenkins hash functions for Rust with a digest-compatible API.
Documentation
use core::cmp::min;
use digest::{FixedOutput, Output, Update};
use super::{Lookup2, GOLDEN_RATIO};

/// Type marker for the word-oriented hash variant.
///
/// This variant operates on arrays of `u32` values and is faster than the byte-oriented
/// variants. It requires that all machines have the same endianness, making it suitable
/// for applications where you control the environment and have word-aligned data.
///
/// # Performance
///
/// This is the fastest variant when working with word-aligned data, as it processes
/// three 32-bit words at a time without byte-level operations.
///
/// # Portability
///
/// This variant requires consistent endianness across all machines in your system.
/// If you need cross-platform compatibility, consider using [`Hash3`] instead.
///
/// [`Hash3`]: crate::lookup2::Hash3
///
/// # Examples
///
/// ```
/// use JenkHash::lookup2::{Lookup2, Hash2};
/// let data: [u32; 3] = [0x12345678, 0x9abcdef0, 0xdeadbeef];
/// let hash = Lookup2::<Hash2>::hash(&data, 0);
/// ```
pub struct Hash2;

impl Lookup2<Hash2> {
    /// Computes the hash of an array of 32-bit words.
    ///
    /// This variant is optimized for word-aligned data and is faster than the
    /// byte-oriented variants. It requires that all machines have the same
    /// endianness. The input length is measured in 32-bit words, not bytes.
    ///
    /// # Arguments
    ///
    /// * `data` - A slice of 32-bit words to hash
    /// * `initial` - The initial seed value (can be 0 or a previous hash value for chaining)
    ///
    /// # Returns
    ///
    /// A 32-bit hash value.
    ///
    /// # Examples
    ///
    /// ```
    /// use JenkHash::lookup2::{Lookup2, Hash2};
    ///
    /// let data: [u32; 3] = [0x12345678, 0x9abcdef0, 0xdeadbeef];
    /// let hash = Lookup2::<Hash2>::hash(&data, 0);
    /// assert_eq!(hash, 0xA94E6CA0);
    /// ```
    #[rustfmt::skip]
    pub fn hash(mut data: &[u32], initial: u32) -> u32 {
        let starting_length = data.len() as u32;
        let mut state = [GOLDEN_RATIO, GOLDEN_RATIO, initial];

        while data.len() >= 3 {
            state[0] = state[0].wrapping_add(data[0]);
            state[1] = state[1].wrapping_add(data[1]);
            state[2] = state[2].wrapping_add(data[2]);
            state = Self::mix(state);
            data = &data[3..];
        }

        state[2] = state[2].wrapping_add((starting_length << 2));

        if data.len() >= 2 { state[1] = state[1].wrapping_add(data[1]) }
        if data.len() >= 1 { state[0] = state[0].wrapping_add(data[0]) }

        state = Self::mix(state);

        state[2]
    }
}