#![no_std]
#![recursion_limit = "130"]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
use core::{char, mem};
#[cfg(feature = "doc-comment")]
extern crate doc_comment;
#[cfg(feature = "doc-comment")]
doc_comment::doctest!("../README.md");
pub trait GenerateRand {
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self;
}
pub trait Random {
type Error;
fn try_fill_bytes(&mut self, buf: &mut [u8]) -> Result<(), Self::Error>;
fn fill_bytes(&mut self, buf: &mut [u8]) {
if self.try_fill_bytes(buf).is_err() {
panic!("Failed getting randmness");
}
}
fn gen<T: GenerateRand>(&mut self) -> T {
T::generate(self)
}
fn get_u8(&mut self) -> u8 {
let mut buf = [0u8; 1];
self.fill_bytes(&mut buf);
buf[0]
}
fn get_u16(&mut self) -> u16 {
let mut buf = [0u8; 2];
self.fill_bytes(&mut buf);
unsafe { mem::transmute(buf) }
}
fn get_u32(&mut self) -> u32 {
let mut buf = [0u8; 4];
self.fill_bytes(&mut buf);
unsafe { mem::transmute(buf) }
}
fn get_u64(&mut self) -> u64 {
let mut buf = [0u8; 8];
self.fill_bytes(&mut buf);
unsafe { mem::transmute(buf) }
}
#[cfg(target_pointer_width = "64")]
fn get_usize(&mut self) -> usize {
self.get_u64() as usize
}
#[cfg(target_pointer_width = "32")]
fn get_usize(&mut self) -> usize {
self.get_u32() as usize
}
#[cfg(target_pointer_width = "16")]
fn get_usize(&mut self) -> usize {
self.get_u16() as usize
}
#[cfg(feature = "u128")]
fn get_u128(&mut self) -> u128 {
let mut buf = [0u8; 16];
self.fill_bytes(&mut buf);
unsafe { mem::transmute(buf) }
}
fn get_bool(&mut self) -> bool {
let bit = self.get_u8() & 0b1000_0000;
debug_assert!(bit < 2);
bit == 1
}
}
impl GenerateRand for u8 {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_u8()
}
}
impl GenerateRand for u16 {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_u16()
}
}
impl GenerateRand for u32 {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_u32()
}
}
impl GenerateRand for u64 {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_u64()
}
}
impl GenerateRand for usize {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_usize()
}
}
#[cfg(feature = "u128")]
impl GenerateRand for u128 {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_u128()
}
}
impl GenerateRand for char {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
loop {
if let Some(c) = char::from_u32(rand.get_u32()) {
return c;
}
}
}
}
impl GenerateRand for bool {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
rand.get_bool()
}
}
impl GenerateRand for f64 {
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
let mut exponent: i32 = -64;
let mut significand = rand.get_u64();
while significand == 0 {
exponent -= 64;
if exponent < -1074i32 {
unreachable!("The randomness is broken, got 0 16 times. (prob of 1/2^1024)");
}
significand = rand.get_u64();
}
let shift = significand.leading_zeros() as i32;
if shift > 0 {
exponent -= shift;
significand <<= shift;
significand |= rand.get_u64() >> (64 - shift);
}
significand |= 1;
significand as f64 * exp2(exponent)
}
}
impl GenerateRand for f32 {
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
let mut exponent: i32 = -32;
let mut significand = rand.get_u32();
while significand == 0 {
exponent -= 32;
if exponent < -149i32 {
unreachable!("The randomness is broken, got 0 5 times. (prob of 1/2^160)");
}
significand = rand.get_u32();
}
let shift = significand.leading_zeros() as i32;
if shift != 0 {
exponent -= shift;
significand <<= shift;
significand |= rand.get_u32() >> (32 - shift);
}
significand |= 1;
significand as f32 * exp2f(exponent)
}
}
fn exp2f(exp: i32) -> f32 {
debug_assert!(exp > -127);
let bits = ((127i32 + exp) as u32) << 23u32;
unsafe { mem::transmute(bits) } }
fn exp2(exp: i32) -> f64 {
debug_assert!(exp > -1023);
let bits = ((1023i32 + exp) as u64) << 52u64;
unsafe { mem::transmute(bits) } }
macro_rules! impl_generate_rand_ifromu {
($ity:ty, $uty: ty) => {
impl GenerateRand for $ity {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
debug_assert_eq!(mem::size_of::<$ity>(), mem::size_of::<$uty>());
<$uty>::generate(rand) as $ity
}
}
};
}
impl_generate_rand_ifromu! {i8, u8}
impl_generate_rand_ifromu! {i16, u16}
impl_generate_rand_ifromu! {i32, u32}
impl_generate_rand_ifromu! {i64, u64}
impl_generate_rand_ifromu! {isize, usize}
#[cfg(feature = "u128")]
impl_generate_rand_ifromu! {i128, u128}
macro_rules! array_impls {
{$N:expr, $t:ident $($ts:ident)*} => {
impl<T: GenerateRand> GenerateRand for [T; $N] {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
[rand.gen::<$t>(), $(rand.gen::<$ts>()),*]
}
}
array_impls!{($N - 1), $($ts)*}
};
{$N:expr,} => {
impl<T: GenerateRand> GenerateRand for [T; $N] {
#[inline]
fn generate<R: Random + ?Sized>(_: &mut R) -> Self { [] }
}
};
}
array_impls! {128, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T
T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T}
macro_rules! tuple_impls {
($(
($($T:ident),+),
)+) => {
$(
impl<$($T: GenerateRand),+> GenerateRand for ($($T,)+) {
#[inline]
fn generate<R: Random + ?Sized>(rand: &mut R) -> Self {
($({ let x: $T = rand.gen(); x},)+)
}
}
)+
}
}
tuple_impls! {
(A),
(A, B),
(A, B, C),
(A, B, C, D),
(A, B, C, D, E),
(A, B, C, D, E, F),
(A, B, C, D, E, F, G),
(A, B, C, D, E, F, G, H),
(A, B, C, D, E, F, G, H, I),
(A, B, C, D, E, F, G, H, I, J),
(A, B, C, D, E, F, G, H, I, J, K),
(A, B, C, D, E, F, G, H, I, J, K, L),
(A, B, C, D, E, F, G, H, I, J, K, L, M),
(A, B, C, D, E, F, G, H, I, J, K, L, M, N),
(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O),
(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
}