/// A fast seedable 32-bit hash function.
pub fn hash_u32(mut n: u32, seed: u32) -> u32 {
    // We rotate the bits of `seed` so it's unlikely to interact with `n`
    // in bad ways if they're both e.g. incrementing.  The particular
    // rotation constant used here isn't special.
    n ^= seed.rotate_left(23);

    // From https://github.com/skeeto/hash-prospector
    n ^= n >> 16;
    n = n.wrapping_mul(0x21f0aaad);
    n ^= n >> 15;
    n = n.wrapping_mul(0xd35a2d97);
    n ^= n >> 15;

    // Xor by a random number so input zero doesn't map to output zero.
    // The particular number used here isn't special.
    n ^ 0xe6fe3beb
}

/// A fast seedable 64-bit hash function.
pub fn hash_u64(mut n: u64, seed: u64) -> u64 {
    // We rotate the bits of `seed` so it's unlikely to interact with `n`
    // in bad ways if they're both e.g. incrementing.  The particular
    // rotation constant used here isn't special.
    n ^= seed.rotate_left(47);

    // From https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
    n ^= n >> 30;
    n = n.wrapping_mul(0xbf58476d1ce4e5b9);
    n ^= n >> 27;
    n = n.wrapping_mul(0x94d049bb133111eb);
    n ^= n >> 31;

    // Xor by a random number so input zero doesn't map to output zero.
    // The particular number used here isn't special.
    n ^ 0x4acc3f27cc712c9d
}

/// Returns a random float in [0, 1] based on 'n' and a seed.
/// Generally use n for getting a bunch of different random
/// numbers, and use seed to vary between runs.
pub fn hash_u32_to_f32(n: u32, seed: u32) -> f32 {
    const INV_MAX: f32 = 1.0 / std::u32::MAX as f32;
    hash_u32(n, seed) as f32 * INV_MAX
}
