prns 1.0.0

A Rust implementation of the PRNS fast random-access pseudo-random number generator
Documentation
//! Implements the prns PRNG
//!
//! https://github.com/Marc-B-Reynolds/Stand-alone-junk/blob/master/src/SFH/prns.h

#![no_std]

use core::num::Wrapping;

#[derive(Default)]
pub struct Prns {
    i: Wrapping<u64>,
}

const PRNS_MIX_S0: usize = 31;
const PRNS_MIX_S1: usize = 27;
const PRNS_MIX_S2: usize = 33;
const PRNS_MIX_M0: u64 = 0x7fb5d329728ea185;
const PRNS_MIX_M1: u64 = 0x81dadef4bc2dd44d;
const PRNS_WEYL: Wrapping<u64> = Wrapping(0x61c8864680b583eb);
const PRNS_WEYL_I: Wrapping<u64> = Wrapping(0x0e217c1e66c88cc3);

impl Prns {
    pub fn mix(mut x: Wrapping<u64>) -> u64 {
        x ^= x >> PRNS_MIX_S0;
        x *= PRNS_MIX_M0;
        x ^= x >> PRNS_MIX_S1;
        x *= PRNS_MIX_M1;
        x ^= x >> PRNS_MIX_S2;
        x.0
    }

    pub fn tell(&self) -> u64 {
        (self.i * PRNS_WEYL_I).0
    }

    pub fn at(n: u64) -> u64 {
        Self::mix(PRNS_WEYL * Wrapping(n))
    }

    pub fn peek(&self) -> u64 {
        Self::mix(self.i)
    }

    #[allow(clippy::should_implement_trait)]
    pub fn next(&mut self) -> u64 {
        let r = Self::mix(self.i);
        self.i += PRNS_WEYL;
        r
    }

    pub fn prev(&mut self) -> u64 {
        let r = Self::mix(self.i);
        self.i -= PRNS_WEYL;
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let mut rng = Prns::default();
        assert_eq!(rng.next(), 0);
        assert_eq!(rng.next(), 16997136850213553216);
        assert_eq!(rng.next(), 16093987548892232582);
        assert_eq!(rng.next(), 7101631883897567084);
        assert_eq!(rng.next(), 197735962506217616);

        assert_eq!(rng.tell(), 5);
        assert_eq!(Prns::at(5), 12951196477222847639);
        assert_eq!(rng.peek(), 12951196477222847639);
        assert_eq!(rng.prev(), 12951196477222847639);
    }
}