sva-formula 0.7.17

Laws in t and f: the normal form, the rule table, and the observations a law answers without sampling
Documentation
// Concern: the two-lane FNV mixer every content address in this workspace is built from | Non-concern: what any one address keys (hash.rs, sva-engine's cache and refs) | IO: (words) -> Hash

use crate::hash::Hash;

/// Two independently primed FNV-1a lanes over one stream of words. `ROTATE` staggers the
/// second lane, and each caller's own value is part of its address space: change one and
/// every address that value ever produced is retired with it.
#[derive(Clone, Copy)]
pub struct Lanes<const ROTATE: u32>(u64, u64);

impl<const ROTATE: u32> Default for Lanes<ROTATE> {
    fn default() -> Lanes<ROTATE> {
        Lanes(0xcbf2_9ce4_8422_2325, 0x9e37_79b9_7f4a_7c15)
    }
}

impl<const ROTATE: u32> Lanes<ROTATE> {
    /// Continuing from an address already built, rather than from the primes.
    pub fn from(seed: Hash) -> Lanes<ROTATE> {
        Lanes(seed.0, seed.1)
    }

    pub fn word(&mut self, part: u64) {
        self.0 = (self.0 ^ part).wrapping_mul(0x0000_0100_0000_01b3);
        self.1 = (self.1 ^ part.rotate_left(ROTATE)).wrapping_mul(0x8803_55f2_1e6d_1965);
    }

    pub fn finish(self) -> Hash {
        Hash(self.0, self.1)
    }
}