1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
//! ## Weyl, a fast PRNG based on the Middle Square Weyl Sequence.
//! Warning: Not cryptographically secure.

#[macro_use]
extern crate lazy_static;

use std::sync::Mutex;
use std::time::{SystemTime, UNIX_EPOCH};

/// Middle Square Weyl Sequence PRNG
/// In other words it generates random numbers.
pub struct Generator {
    x: u64,
    w: u64,
    s: u64,
    seed: u64, // original seed
}

impl Generator {
    pub fn new(seed: u64) -> Generator {
        Generator {
            x: 0,
            w: 0,
            s: (seed << 1).wrapping_add(0xb5ad4eceda1ce2a9),
            seed: seed,
        }
    }
    /// generates a random u64
    pub fn u64(&mut self) -> u64 {
        self.w = self.w.wrapping_add(self.s);
        self.x = (self.x.wrapping_mul(self.x).wrapping_add(self.w) >> 32)
            | (self.x.wrapping_mul(self.x).wrapping_add(self.w) << 32);
        self.x
    }
    /// generates a random f64
    pub fn f64(&mut self) -> f64 {
        self.u64() as f64 / ((0xFFFFFFFFFFFFFFFFu64 as f64) + 1.0)
    }
    /// fill bytes slice with random data
    pub fn fill(&mut self, bytes: &mut [u8]) {
        let mut rval = self.u64();
        let mut i = 0;
        for b in bytes {
            *b = (rval & 0xff) as u8;
            rval >>= 8;
            i += 1;
            if i & 7 == 0 {
                rval = self.u64();
            }
        }
    }
}

lazy_static! {
    static ref RAND: Mutex<Generator> = {
        let seed = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64;
        Mutex::new(Generator::new(seed))
    };
}

pub fn last_seed() -> u64 {
    RAND.lock().unwrap().seed
}
pub fn seed(seed: u64) {
    let mut rc = RAND.lock().unwrap();
    *rc = Generator::new(seed);
}
/// returns a random u64
pub fn u64() -> u64 {
    RAND.lock().unwrap().u64()
}
/// returns a random f64
pub fn f64() -> f64 {
    RAND.lock().unwrap().f64()
}

/// fill bytes slice with random data
pub fn fill(bytes: &mut [u8]) {
    RAND.lock().unwrap().fill(bytes)
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn various() {
        assert!(last_seed() != 0);
        assert!(u64() != 0);
        let mut bytes = vec![0; 64];
        fill(&mut bytes);
        let mut ok = false;
        for b in &bytes {
            if *b != 0 {
                ok = true;
                break;
            }
        }
        assert!(ok);
    }
}