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
104
105
106
107
108
109
110
/// Implementation of the wyrand RNG algorithm.  
/// More details can be seen at https://github.com/wangyi-fudan/wyhash
#[cfg(feature = "wyrand")]
pub mod wyrand;
#[cfg(feature = "wyrand")]
pub use wyrand::WyRand;

use crate::RNG_STATE_GLOBAL;
use core::sync::atomic::Ordering;

/// A trait that represents a random number generator.
/// It is expected that
pub trait RNG {
	/// Generates a random 64-bit integer, seeding from the internal state.
	fn rand(&mut self) -> u64;
	/// Generates a random 64-bit integer, with a custom seed.
	fn rand_with_seed(seed: u64) -> u64;
	/// Reseeds the RNG using a custom seed.
	fn reseed(&mut self, new_seed: u64);
	/// Creates a new RNG instance, seeding it from ourselves.
	fn clone(&mut self) -> Self;
	/// Generates a random 64-bit integer in a custom range, seeding from the internal state.
	fn rand_range(&mut self, lower: u64, upper: u64) -> u64 {
		let random_number = self.rand();
		(random_number % (upper - lower + 1)) + lower
	}
	/// Generates a random 64-bit integer in a custom range, with a custom seed.
	fn rand_range_with_seed(&mut self, seed: u64, lower: u64, upper: u64) -> u64 {
		let random_number = Self::rand_with_seed(seed);
		(random_number % (upper - lower + 1)) + lower
	}
	/// Generates a random 64-bit integer, seeding from the global state.  
	/// Note that _this is slower than an internal state_, due to use of atomics.
	fn rand_global() -> u64 {
		let seed = RNG_STATE_GLOBAL.load(Ordering::Acquire);
		let random_number = Self::rand_with_seed(seed);
		RNG_STATE_GLOBAL.compare_and_swap(seed, random_number, Ordering::Release);
		random_number
	}
	/// Generates a random 64-bit integer in a custom range, seeding from the global state.
	fn rand_global_range(lower: u64, upper: u64) -> u64 {
		let random_number = Self::rand_global();
		(random_number % (upper - lower + 1)) + lower
	}
}

pub trait RandomGen<R: RNG> {
	/// Return a random instance of the implementing type.
	fn generate(r: &mut R) -> Self;
}

impl<R: RNG> RandomGen<R> for u8 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFF) as u8
	}
}

impl<R: RNG> RandomGen<R> for u16 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFFFF) as u16
	}
}

impl<R: RNG> RandomGen<R> for u32 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFFFFFFFF) as u32
	}
}

impl<R: RNG> RandomGen<R> for u64 {
	fn generate(r: &mut R) -> Self {
		r.rand()
	}
}

impl<R: RNG> RandomGen<R> for usize {
	fn generate(r: &mut R) -> Self {
		r.rand() as usize
	}
}

impl<R: RNG> RandomGen<R> for i8 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFF) as i8
	}
}

impl<R: RNG> RandomGen<R> for i16 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFFFF) as i16
	}
}

impl<R: RNG> RandomGen<R> for i32 {
	fn generate(r: &mut R) -> Self {
		(r.rand() & 0xFFFFFFFF) as i32
	}
}

impl<R: RNG> RandomGen<R> for i64 {
	fn generate(r: &mut R) -> Self {
		r.rand() as i64
	}
}

impl<R: RNG> RandomGen<R> for isize {
	fn generate(r: &mut R) -> Self {
		r.rand() as isize
	}
}