rain-lang 0.0.1

An implementation of an RVSDG in Rust with a concept of lifetimes
Documentation
/*!
Miscellaneous utilities
*/

use std::convert::Infallible;
use std::hash::Hasher;

/// A type may generically hold errors but is guaranteed never to do so in a particular instance.
/// Stand-in for `#[feature(unwrap_infallible)]`
pub trait AlwaysOk<T> {
    /// Extract a value of a type from a generic error type statically guaranteed never
    /// to hold an error.
    fn aok(self) -> T;
}

impl<T, I> AlwaysOk<T> for Result<T, I> where I: Into<Infallible> {
    #[inline] fn aok(self) -> T {
        match self {
            Ok(ok) => ok,
            Err(err) => { let _err: Infallible = err.into(); match _err {} }
        }
    }
}

/// A hash function which simply returns the last eight bytes of input.
#[derive(Debug, Copy, Clone, Default)]
pub struct PassThroughHasher {
    /// The starting value of the hasher
    pub starting_value: u64
}

impl Hasher for PassThroughHasher {
    #[inline(always)] fn finish(&self) -> u64 { self.starting_value }
    #[inline(always)] fn write(&mut self, bytes: &[u8]) {
        let mut new_value = [0; 8];
        let mut i = 0;
        for byte in bytes.iter().rev() {
            if i >= 8 { break }
            new_value[7 - i] = *byte;
            i += 1;
        }
        let old_value = self.starting_value.to_ne_bytes();
        for byte in old_value.iter().rev() {
            if i >= 8 { break }
            new_value[7 - i] = *byte;
            i += 1;
        }
        self.starting_value = u64::from_ne_bytes(new_value);
    }
    #[inline(always)] fn write_u64(&mut self, value: u64) { self.starting_value = value }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand_xoshiro::Xoshiro256StarStar;
    use rand::SeedableRng;
    use rand::Rng;

    const RNG_SEED: u64 = 0xCAFEDECAF2832;

    #[test]
    fn pass_through_hasher_works() {
        let mut hasher = PassThroughHasher::default();
        assert_eq!(hasher.finish(), 0);
        hasher.write(&[1, 2, 3, 4]);
        assert_eq!(hasher.finish(), u64::from_ne_bytes([0, 0, 0, 0, 1, 2, 3, 4]));
        hasher.write(&[5, 6, 7, 8]);
        assert_eq!(hasher.finish(), u64::from_ne_bytes([1, 2, 3, 4, 5, 6, 7, 8]));

        let mut rng = Xoshiro256StarStar::seed_from_u64(RNG_SEED);
        for _ in 0..100 {
            let val = rng.gen();
            hasher.write_u64(val);
            assert_eq!(hasher.finish(), val);
            hasher.write(&val.to_ne_bytes());
            assert_eq!(hasher.finish(), val);
        }
    }
}