use crate::{misc::AsOrPanic, Integer};
use core::{
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ptr,
};
use gmp_mpfr_sys::gmp::{self, limb_t, mpz_t, randfnptr_t, randseed_t, randstate_t};
use libc::{c_ulong, c_void};
use std::process;
#[derive(Debug)]
#[repr(transparent)]
pub struct RandState<'a> {
inner: randstate_t,
phantom: PhantomData<&'a dyn RandGen>,
}
impl Default for RandState<'_> {
#[inline]
fn default() -> RandState<'static> {
RandState::new()
}
}
impl Clone for RandState<'_> {
#[inline]
fn clone(&self) -> RandState<'static> {
unsafe {
let mut inner = MaybeUninit::uninit();
gmp::randinit_set(inner.as_mut_ptr(), self.as_raw());
let inner = inner.assume_init();
if inner.seed.d.is_null() {
panic!("`RandGen::boxed_clone` returned `None`");
}
RandState {
inner,
phantom: PhantomData,
}
}
}
}
impl Drop for RandState<'_> {
#[inline]
fn drop(&mut self) {
unsafe {
gmp::randclear(self.as_raw_mut());
}
}
}
unsafe impl Send for RandState<'_> {}
unsafe impl Sync for RandState<'_> {}
impl RandState<'_> {
#[inline]
pub fn new() -> RandState<'static> {
RandState::new_mersenne_twister()
}
pub fn new_mersenne_twister() -> RandState<'static> {
unsafe {
let mut inner = MaybeUninit::uninit();
gmp::randinit_mt(inner.as_mut_ptr());
RandState {
inner: inner.assume_init(),
phantom: PhantomData,
}
}
}
pub fn new_linear_congruential(a: &Integer, c: u32, m: u32) -> RandState<'static> {
unsafe {
let mut inner = MaybeUninit::uninit();
gmp::randinit_lc_2exp(inner.as_mut_ptr(), a.as_raw(), c.into(), m.into());
RandState {
inner: inner.assume_init(),
phantom: PhantomData,
}
}
}
pub fn new_linear_congruential_size(size: u32) -> Option<RandState<'static>> {
unsafe {
let mut inner = MaybeUninit::uninit();
if gmp::randinit_lc_2exp_size(inner.as_mut_ptr(), size.into()) != 0 {
Some(RandState {
inner: inner.assume_init(),
phantom: PhantomData,
})
} else {
None
}
}
}
pub fn new_custom(custom: &mut dyn RandGen) -> RandState<'_> {
let b: Box<&mut dyn RandGen> = Box::new(custom);
let r_ptr: *mut &mut dyn RandGen = Box::into_raw(b);
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: &CUSTOM_FUNCS,
};
RandState {
inner,
phantom: PhantomData,
}
}
pub fn new_custom_boxed(custom: Box<dyn RandGen>) -> RandState<'static> {
let b: Box<Box<dyn RandGen>> = Box::new(custom);
let r_ptr: *mut Box<dyn RandGen> = Box::into_raw(b);
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: &CUSTOM_BOXED_FUNCS,
};
RandState {
inner,
phantom: PhantomData,
}
}
#[inline]
pub unsafe fn from_raw(raw: randstate_t) -> RandState<'static> {
RandState {
inner: raw,
phantom: PhantomData,
}
}
#[inline]
pub fn into_raw(self) -> randstate_t {
assert!(
!ptr::eq(self.inner.algdata, &CUSTOM_FUNCS)
&& !ptr::eq(self.inner.algdata, &THREAD_CUSTOM_FUNCS),
"cannot convert custom `RandState` into raw, \
consider using `new_custom_boxed` instead of `new_custom`"
);
let m = ManuallyDrop::new(self);
m.inner
}
#[inline]
pub fn as_raw(&self) -> *const randstate_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut randstate_t {
&mut self.inner
}
#[inline]
pub fn into_custom_boxed(self) -> Result<Box<dyn RandGen>, Self> {
if !ptr::eq(self.inner.algdata, &CUSTOM_BOXED_FUNCS) {
return Err(self);
}
let m = ManuallyDrop::new(self);
let r_ptr = m.inner.seed.d as *mut Box<dyn RandGen>;
let boxed_box: Box<Box<dyn RandGen>> = unsafe { Box::from_raw(r_ptr) };
Ok(*boxed_box)
}
#[inline]
pub fn seed(&mut self, seed: &Integer) {
unsafe {
gmp::randseed(self.as_raw_mut(), seed.as_raw());
}
}
#[inline]
pub fn bits(&mut self, bits: u32) -> u32 {
assert!(bits <= 32, "bits out of range");
unsafe { gmp::urandomb_ui(self.as_raw_mut(), bits.into()) as u32 }
}
#[inline]
pub fn below(&mut self, bound: u32) -> u32 {
assert_ne!(bound, 0, "cannot be below zero");
unsafe { gmp::urandomm_ui(self.as_raw_mut(), bound.into()) as u32 }
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct ThreadRandState<'a> {
inner: randstate_t,
phantom: PhantomData<&'a dyn ThreadRandGen>,
}
impl Clone for ThreadRandState<'_> {
#[inline]
fn clone(&self) -> ThreadRandState<'static> {
unsafe {
let mut inner = MaybeUninit::uninit();
gmp::randinit_set(inner.as_mut_ptr(), self.as_raw());
let inner = inner.assume_init();
if inner.seed.d.is_null() {
panic!("`ThreadRandGen::boxed_clone` returned `None`");
}
ThreadRandState {
inner,
phantom: PhantomData,
}
}
}
}
impl Drop for ThreadRandState<'_> {
#[inline]
fn drop(&mut self) {
unsafe {
gmp::randclear(self.as_raw_mut());
}
}
}
impl ThreadRandState<'_> {
pub fn new_custom(custom: &mut dyn ThreadRandGen) -> ThreadRandState<'_> {
let b: Box<&mut dyn ThreadRandGen> = Box::new(custom);
let r_ptr: *mut &mut dyn ThreadRandGen = Box::into_raw(b);
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: &THREAD_CUSTOM_FUNCS,
};
ThreadRandState {
inner,
phantom: PhantomData,
}
}
pub fn new_custom_boxed(custom: Box<dyn ThreadRandGen>) -> ThreadRandState<'static> {
let b: Box<Box<dyn ThreadRandGen>> = Box::new(custom);
let r_ptr: *mut Box<dyn ThreadRandGen> = Box::into_raw(b);
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: &THREAD_CUSTOM_BOXED_FUNCS,
};
ThreadRandState {
inner,
phantom: PhantomData,
}
}
#[inline]
pub unsafe fn from_raw(raw: randstate_t) -> ThreadRandState<'static> {
ThreadRandState {
inner: raw,
phantom: PhantomData,
}
}
#[inline]
pub fn into_raw(self) -> randstate_t {
assert!(
!ptr::eq(self.inner.algdata, &CUSTOM_FUNCS)
&& !ptr::eq(self.inner.algdata, &THREAD_CUSTOM_FUNCS),
"cannot convert custom `ThreadRandState` into raw, \
consider using `new_custom_boxed` instead of `new_custom`"
);
let m = ManuallyDrop::new(self);
m.inner
}
#[inline]
pub fn as_raw(&self) -> *const randstate_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut randstate_t {
&mut self.inner
}
#[inline]
pub fn into_custom_boxed(self) -> Result<Box<dyn ThreadRandGen>, Self> {
if !ptr::eq(self.inner.algdata, &THREAD_CUSTOM_BOXED_FUNCS) {
return Err(self);
}
let m = ManuallyDrop::new(self);
let r_ptr = m.inner.seed.d as *mut Box<dyn ThreadRandGen>;
let boxed_box: Box<Box<dyn ThreadRandGen>> = unsafe { Box::from_raw(r_ptr) };
Ok(*boxed_box)
}
#[inline]
pub fn seed(&mut self, seed: &Integer) {
unsafe {
gmp::randseed(self.as_raw_mut(), seed.as_raw());
}
}
#[inline]
pub fn bits(&mut self, bits: u32) -> u32 {
assert!(bits <= 32, "bits out of range");
unsafe { gmp::urandomb_ui(self.as_raw_mut(), bits.into()) as u32 }
}
#[inline]
pub fn below(&mut self, bound: u32) -> u32 {
assert_ne!(bound, 0, "cannot be below zero");
unsafe { gmp::urandomm_ui(self.as_raw_mut(), bound.into()) as u32 }
}
}
pub trait RandGen: Send + Sync {
fn gen(&mut self) -> u32;
fn gen_bits(&mut self, bits: u32) -> u32 {
let gen = self.gen();
match bits {
0 => 0,
1..=31 => gen >> (32 - bits),
_ => gen,
}
}
#[inline]
fn seed(&mut self, seed: &Integer) {
let _ = seed;
}
#[inline]
fn boxed_clone(&self) -> Option<Box<dyn RandGen>> {
None
}
}
pub trait ThreadRandGen {
fn gen(&mut self) -> u32;
fn gen_bits(&mut self, bits: u32) -> u32 {
let gen = self.gen();
match bits {
0 => 0,
1..=32 => gen >> (32 - bits),
_ => gen,
}
}
#[inline]
fn seed(&mut self, seed: &Integer) {
let _ = seed;
}
#[inline]
fn boxed_clone(&self) -> Option<Box<dyn ThreadRandGen>> {
None
}
}
static_assert_same_layout!(RandState<'_>, randstate_t);
static_assert_same_layout!(ThreadRandState<'_>, randstate_t);
unsafe extern "C" fn abort_seed(_: *mut randstate_t, _: *const mpz_t) {
process::abort();
}
unsafe extern "C" fn abort_get(_: *mut randstate_t, _: *mut limb_t, _: c_ulong) {
process::abort();
}
unsafe extern "C" fn abort_clear(_: *mut randstate_t) {
process::abort();
}
unsafe extern "C" fn abort_iset(_: *mut randstate_t, _: *const randstate_t) {
process::abort();
}
unsafe extern "C" fn custom_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn RandGen;
(*r_ptr).seed(&*cast_ptr!(seed, Integer));
}
unsafe extern "C" fn custom_get(rstate: *mut randstate_t, dest: *mut limb_t, nbits: c_ulong) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn RandGen;
gen_bits(*r_ptr, dest, nbits);
}
unsafe extern "C" fn custom_clear(rstate: *mut randstate_t) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn RandGen;
drop(Box::from_raw(r_ptr));
}
unsafe extern "C" fn custom_iset(dst: *mut randstate_t, src: *const randstate_t) {
let r_ptr = (*src).seed.d as *const &mut dyn RandGen;
gen_copy(*r_ptr, dst);
}
unsafe extern "C" fn custom_boxed_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn RandGen>;
(*r_ptr).seed(&*cast_ptr!(seed, Integer));
}
unsafe extern "C" fn custom_boxed_get(rstate: *mut randstate_t, dest: *mut limb_t, nbits: c_ulong) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn RandGen>;
gen_bits(&mut **r_ptr, dest, nbits);
}
unsafe extern "C" fn custom_boxed_clear(rstate: *mut randstate_t) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn RandGen>;
drop(Box::from_raw(r_ptr));
}
unsafe extern "C" fn custom_boxed_iset(dst: *mut randstate_t, src: *const randstate_t) {
let r_ptr = (*src).seed.d as *const Box<dyn RandGen>;
gen_copy(&**r_ptr, dst);
}
unsafe extern "C" fn thread_custom_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn ThreadRandGen;
(*r_ptr).seed(&*cast_ptr!(seed, Integer));
}
unsafe extern "C" fn thread_custom_get(
rstate: *mut randstate_t,
dest: *mut limb_t,
nbits: c_ulong,
) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn ThreadRandGen;
thread_gen_bits(*r_ptr, dest, nbits);
}
unsafe extern "C" fn thread_custom_clear(rstate: *mut randstate_t) {
let r_ptr = (*rstate).seed.d as *mut &mut dyn ThreadRandGen;
drop(Box::from_raw(r_ptr));
}
unsafe extern "C" fn thread_custom_iset(dst: *mut randstate_t, src: *const randstate_t) {
let r_ptr = (*src).seed.d as *const &mut dyn ThreadRandGen;
thread_gen_copy(*r_ptr, dst);
}
unsafe extern "C" fn thread_custom_boxed_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn ThreadRandGen>;
(*r_ptr).seed(&*cast_ptr!(seed, Integer));
}
unsafe extern "C" fn thread_custom_boxed_get(
rstate: *mut randstate_t,
dest: *mut limb_t,
nbits: c_ulong,
) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn ThreadRandGen>;
thread_gen_bits(&mut **r_ptr, dest, nbits);
}
unsafe extern "C" fn thread_custom_boxed_clear(rstate: *mut randstate_t) {
let r_ptr = (*rstate).seed.d as *mut Box<dyn ThreadRandGen>;
drop(Box::from_raw(r_ptr));
}
unsafe extern "C" fn thread_custom_boxed_iset(dst: *mut randstate_t, src: *const randstate_t) {
let r_ptr = (*src).seed.d as *const Box<dyn ThreadRandGen>;
thread_gen_copy(&**r_ptr, dst);
}
#[cfg(gmp_limb_bits_64)]
unsafe fn gen_bits(gen: &mut dyn RandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 64, nbits % 64);
let limbs = limbs.as_or_panic::<isize>();
for i in 0..limbs {
let n = u64::from(gen.gen()) | u64::from(gen.gen()) << 32;
*dest.offset(i) = n.as_or_panic();
}
if rest >= 32 {
let mut n = u64::from(gen.gen());
if rest > 32 {
let mask = !(!0 << (rest - 32));
n |= u64::from(gen.gen_bits((rest - 32).as_or_panic()) & mask) << 32;
}
*dest.offset(limbs) = n.as_or_panic();
} else if rest > 0 {
let mask = !(!0 << rest);
let n = u64::from(gen.gen_bits(rest.as_or_panic()) & mask);
*dest.offset(limbs) = n.as_or_panic();
}
}
#[cfg(gmp_limb_bits_32)]
unsafe fn gen_bits(gen: &mut dyn RandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 32, nbits % 32);
let limbs = limbs.as_or_panic::<isize>();
for i in 0..limbs {
*dest.offset(i) = gen.gen().as_or_panic();
}
if rest > 0 {
let mask = !(!0 << rest);
*dest.offset(limbs) = (gen.gen_bits(rest.as_or_panic()) & mask).as_or_panic();
}
}
unsafe fn gen_copy(gen: &dyn RandGen, dst: *mut randstate_t) {
let (dst_r_ptr, funcs) = if let Some(other) = gen.boxed_clone() {
let b: Box<Box<dyn RandGen>> = Box::new(other);
let dst_r_ptr: *mut Box<dyn RandGen> = Box::into_raw(b);
(dst_r_ptr, &CUSTOM_BOXED_FUNCS)
} else {
(ptr::null_mut(), &ABORT_FUNCS)
};
*dst = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: dst_r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: funcs,
};
}
#[cfg(gmp_limb_bits_64)]
unsafe fn thread_gen_bits(gen: &mut dyn ThreadRandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 64, nbits % 64);
let limbs = limbs.as_or_panic::<isize>();
for i in 0..limbs {
let n = u64::from(gen.gen()) | u64::from(gen.gen()) << 32;
*dest.offset(i) = n.as_or_panic();
}
if rest >= 32 {
let mut n = u64::from(gen.gen());
if rest > 32 {
let mask = !(!0 << (rest - 32));
n |= u64::from(gen.gen_bits((rest - 32).as_or_panic()) & mask) << 32;
}
*dest.offset(limbs) = n.as_or_panic();
} else if rest > 0 {
let mask = !(!0 << rest);
let n = u64::from(gen.gen_bits(rest.as_or_panic()) & mask);
*dest.offset(limbs) = n.as_or_panic();
}
}
#[cfg(gmp_limb_bits_32)]
unsafe fn thread_gen_bits(gen: &mut dyn ThreadRandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 32, nbits % 32);
let limbs = limbs.as_or_panic::<isize>();
for i in 0..limbs {
*dest.offset(i) = gen.gen().as_or_panic();
}
if rest > 0 {
let mask = !(!0 << rest);
*dest.offset(limbs) = (gen.gen_bits(rest.as_or_panic()) & mask).as_or_panic();
}
}
unsafe fn thread_gen_copy(gen: &dyn ThreadRandGen, dst: *mut randstate_t) {
let (dst_r_ptr, funcs) = if let Some(other) = gen.boxed_clone() {
let b: Box<Box<dyn ThreadRandGen>> = Box::new(other);
let dst_r_ptr: *mut Box<dyn ThreadRandGen> = Box::into_raw(b);
(dst_r_ptr, &THREAD_CUSTOM_BOXED_FUNCS)
} else {
(ptr::null_mut(), &ABORT_FUNCS)
};
*dst = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: dst_r_ptr as *mut c_void,
},
alg: MaybeUninit::uninit(),
algdata: funcs,
};
}
static ABORT_FUNCS: randfnptr_t = randfnptr_t {
seed: Some(abort_seed),
get: Some(abort_get),
clear: Some(abort_clear),
iset: Some(abort_iset),
};
static CUSTOM_FUNCS: randfnptr_t = randfnptr_t {
seed: Some(custom_seed),
get: Some(custom_get),
clear: Some(custom_clear),
iset: Some(custom_iset),
};
static CUSTOM_BOXED_FUNCS: randfnptr_t = randfnptr_t {
seed: Some(custom_boxed_seed),
get: Some(custom_boxed_get),
clear: Some(custom_boxed_clear),
iset: Some(custom_boxed_iset),
};
static THREAD_CUSTOM_FUNCS: randfnptr_t = randfnptr_t {
seed: Some(thread_custom_seed),
get: Some(thread_custom_get),
clear: Some(thread_custom_clear),
iset: Some(thread_custom_iset),
};
static THREAD_CUSTOM_BOXED_FUNCS: randfnptr_t = randfnptr_t {
seed: Some(thread_custom_boxed_seed),
get: Some(thread_custom_boxed_get),
clear: Some(thread_custom_boxed_clear),
iset: Some(thread_custom_boxed_iset),
};
pub trait MutRandState: SealedMutRandState {}
mod hide {
use gmp_mpfr_sys::gmp::randstate_t;
#[repr(transparent)]
pub struct Private<'a>(pub(crate) &'a mut randstate_t);
pub trait SealedMutRandState {
fn private(&mut self) -> Private;
}
}
use self::hide::{Private, SealedMutRandState};
impl MutRandState for RandState<'_> {}
impl SealedMutRandState for RandState<'_> {
#[inline]
fn private(&mut self) -> Private {
Private(&mut self.inner)
}
}
impl MutRandState for ThreadRandState<'_> {}
impl SealedMutRandState for ThreadRandState<'_> {
#[inline]
fn private(&mut self) -> Private {
Private(&mut self.inner)
}
}
#[cfg(test)]
mod tests {
use crate::rand::{RandGen, RandState, ThreadRandGen, ThreadRandState};
use core::ptr;
use gmp_mpfr_sys::gmp;
struct SimpleGenerator {
seed: u64,
}
impl RandGen for SimpleGenerator {
fn gen(&mut self) -> u32 {
self.seed = self
.seed
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1);
(self.seed >> 32) as u32
}
fn boxed_clone(&self) -> Option<Box<dyn RandGen>> {
let other = SimpleGenerator { seed: self.seed };
let boxed = Box::new(other);
Some(boxed)
}
}
#[test]
fn check_custom_clone() {
let mut gen = SimpleGenerator { seed: 1 };
let third2;
{
let mut rand1 = RandState::new_custom(&mut gen);
let mut rand2 = rand1.clone();
let first1 = rand1.bits(32);
let first2 = rand2.bits(32);
assert_eq!(first1, first2);
let second1 = rand1.bits(32);
let second2 = rand2.bits(32);
assert_eq!(second1, second2);
assert_ne!(first1, second1);
third2 = rand2.bits(32);
assert_ne!(second2, third2);
}
let mut rand3 = RandState::new_custom_boxed(Box::new(gen));
let mut rand4 = rand3.clone();
let third3 = rand3.bits(32);
let third4 = rand4.bits(32);
assert_eq!(third2, third3);
assert_eq!(third2, third4);
}
struct NoCloneGenerator;
impl RandGen for NoCloneGenerator {
fn gen(&mut self) -> u32 {
0
}
}
#[test]
#[should_panic(expected = "`RandGen::boxed_clone` returned `None`")]
fn check_custom_no_clone() {
let mut gen = NoCloneGenerator;
let rand1 = RandState::new_custom(&mut gen);
let _ = rand1.clone();
}
#[test]
#[should_panic(expected = "cannot convert custom `RandState` into raw")]
fn check_custom_into_raw() {
let mut gen = NoCloneGenerator;
let rand1 = RandState::new_custom(&mut gen);
let _ = rand1.into_raw();
}
struct ThreadSimpleGenerator {
_dummy: *const i32,
seed: u64,
}
impl ThreadRandGen for ThreadSimpleGenerator {
fn gen(&mut self) -> u32 {
self.seed = self
.seed
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1);
(self.seed >> 32) as u32
}
fn boxed_clone(&self) -> Option<Box<dyn ThreadRandGen>> {
let other = ThreadSimpleGenerator {
_dummy: ptr::null(),
seed: self.seed,
};
let boxed = Box::new(other);
Some(boxed)
}
}
#[test]
fn thread_check_custom_clone() {
let mut gen = ThreadSimpleGenerator {
_dummy: ptr::null(),
seed: 1,
};
let third2;
{
let mut rand1 = ThreadRandState::new_custom(&mut gen);
let mut rand2 = rand1.clone();
let first1 = rand1.bits(32);
let first2 = rand2.bits(32);
assert_eq!(first1, first2);
let second1 = rand1.bits(32);
let second2 = rand2.bits(32);
assert_eq!(second1, second2);
assert_ne!(first1, second1);
third2 = rand2.bits(32);
assert_ne!(second2, third2);
}
let mut rand3 = ThreadRandState::new_custom_boxed(Box::new(gen));
let mut rand4 = rand3.clone();
let third3 = rand3.bits(32);
let third4 = rand4.bits(32);
assert_eq!(third2, third3);
assert_eq!(third2, third4);
}
struct ThreadNoCloneGenerator;
impl ThreadRandGen for ThreadNoCloneGenerator {
fn gen(&mut self) -> u32 {
0
}
}
#[test]
#[should_panic(expected = "`ThreadRandGen::boxed_clone` returned `None`")]
fn thread_check_custom_no_clone() {
let mut gen = ThreadNoCloneGenerator;
let rand1 = ThreadRandState::new_custom(&mut gen);
let _ = rand1.clone();
}
#[test]
#[should_panic(expected = "cannot convert custom `ThreadRandState` into raw")]
fn thread_check_custom_into_raw() {
let mut gen = ThreadNoCloneGenerator;
let rand1 = ThreadRandState::new_custom(&mut gen);
let _ = rand1.into_raw();
}
#[test]
fn thread_check_raw() {
let mut check = RandState::new();
let mut state = unsafe { ThreadRandState::from_raw(check.clone().into_raw()) };
assert_eq!(state.bits(32), check.bits(32));
assert_eq!(
unsafe { gmp::urandomb_ui(state.as_raw_mut(), 32) as u32 },
check.bits(32)
);
let mut raw = state.into_raw();
assert_eq!(
unsafe { gmp::urandomb_ui(&mut raw, 32) as u32 },
check.bits(32)
);
let mut state = unsafe { ThreadRandState::from_raw(raw) };
assert_eq!(state.below(100), check.below(100));
}
#[test]
fn congruential_size() {
assert!(RandState::new_linear_congruential_size(128).is_some());
assert!(RandState::new_linear_congruential_size(129).is_none());
}
}