use crate::Integer;
#[cfg(feature = "std")]
use crate::misc;
use az::Cast;
#[cfg(feature = "std")]
use az::{StrictAs, StrictCast};
use core::ffi::c_ulong;
#[cfg(feature = "std")]
use core::ffi::c_void;
use core::marker::PhantomData;
#[cfg(feature = "std")]
use core::mem::ManuallyDrop;
use core::mem::MaybeUninit;
use core::ptr;
#[cfg(feature = "std")]
use core::ptr::NonNull;
use gmp_mpfr_sys::gmp;
#[cfg(feature = "std")]
use gmp_mpfr_sys::gmp::randseed_t;
use gmp_mpfr_sys::gmp::{limb_t, mpz_t, randfnptr_t, randstate_t};
#[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 ptr::eq(inner.algdata, &ABORT_FUNCS) {
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 {
None
} else {
Some(RandState {
inner: inner.assume_init(),
phantom: PhantomData,
})
}
}
}
#[cfg(feature = "std")]
pub fn new_custom(custom: &mut dyn RandGen) -> RandState<'_> {
let b = Box::<&mut dyn RandGen>::new(custom);
let r_ptr = NonNull::<&mut dyn RandGen>::from(Box::leak(b));
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr.cast::<c_void>(),
},
alg: MaybeUninit::uninit(),
algdata: &CUSTOM_FUNCS,
};
RandState {
inner,
phantom: PhantomData,
}
}
#[cfg(feature = "std")]
pub fn new_custom_boxed(custom: Box<dyn RandGen>) -> RandState<'static> {
let b = Box::<Box<dyn RandGen>>::new(custom);
let r_ptr = NonNull::<Box<dyn RandGen>>::from(Box::leak(b));
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr.cast::<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,
}
}
#[cfg(feature = "std")]
#[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
}
#[cfg(feature = "std")]
#[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.cast::<Box<dyn RandGen>>().as_ptr();
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()) }.cast()
}
#[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()) }.cast()
}
}
#[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 ptr::eq(inner.algdata, &ABORT_FUNCS) {
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<'_> {
#[cfg(feature = "std")]
pub fn new_custom(custom: &mut dyn ThreadRandGen) -> ThreadRandState<'_> {
let b = Box::<&mut dyn ThreadRandGen>::new(custom);
let r_ptr = NonNull::<&mut dyn ThreadRandGen>::from(Box::leak(b));
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr.cast::<c_void>(),
},
alg: MaybeUninit::uninit(),
algdata: &THREAD_CUSTOM_FUNCS,
};
ThreadRandState {
inner,
phantom: PhantomData,
}
}
#[cfg(feature = "std")]
pub fn new_custom_boxed(custom: Box<dyn ThreadRandGen>) -> ThreadRandState<'static> {
let b = Box::<Box<dyn ThreadRandGen>>::new(custom);
let r_ptr = NonNull::<Box<dyn ThreadRandGen>>::from(Box::leak(b));
let inner = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: r_ptr.cast::<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,
}
}
#[cfg(feature = "std")]
#[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
}
#[cfg(feature = "std")]
#[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.cast::<Box<dyn ThreadRandGen>>().as_ptr();
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()) }.cast()
}
#[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()) }.cast()
}
}
pub trait RandGen: Send + Sync {
fn r#gen(&mut self) -> u32;
fn gen_bits(&mut self, bits: u32) -> u32 {
let gener = self.r#gen();
match bits {
0 => 0,
1..=31 => gener >> (32 - bits),
_ => gener,
}
}
#[inline]
fn seed(&mut self, seed: &Integer) {
let _ = seed;
}
#[cfg(feature = "std")]
#[inline]
fn boxed_clone(&self) -> Option<Box<dyn RandGen>> {
None
}
}
pub trait ThreadRandGen {
fn r#gen(&mut self) -> u32;
fn gen_bits(&mut self, bits: u32) -> u32 {
let gener = self.r#gen();
match bits {
0 => 0,
1..=32 => gener >> (32 - bits),
_ => gener,
}
}
#[inline]
fn seed(&mut self, seed: &Integer) {
let _ = seed;
}
#[cfg(feature = "std")]
#[inline]
fn boxed_clone(&self) -> Option<Box<dyn ThreadRandGen>> {
None
}
}
static_assert_same_layout!(RandState<'_>, randstate_t);
static_assert_same_layout!(ThreadRandState<'_>, randstate_t);
static_assert_same_size!(RandState, Option<RandState>);
static_assert_same_size!(ThreadRandState, Option<ThreadRandState>);
unsafe extern "C" fn abort_seed(_: *mut randstate_t, _: *const mpz_t) {
unsafe {
libc::abort();
}
}
unsafe extern "C" fn abort_get(_: *mut randstate_t, _: *mut limb_t, _: c_ulong) {
unsafe {
libc::abort();
}
}
unsafe extern "C" fn abort_clear(_: *mut randstate_t) {
unsafe {
libc::abort();
}
}
unsafe extern "C" fn abort_iset(_: *mut randstate_t, _: *const randstate_t) {
unsafe {
libc::abort();
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn RandGen>().as_ptr();
let seed = misc::cast_ptr(seed);
unsafe {
(*r_ptr).seed(&*seed);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_get(rstate: *mut randstate_t, dest: *mut limb_t, nbits: c_ulong) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn RandGen>().as_ptr();
unsafe {
gen_bits(*r_ptr, dest, nbits);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_clear(rstate: *mut randstate_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn RandGen>().as_ptr();
drop(unsafe { Box::from_raw(r_ptr) });
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_iset(dst: *mut randstate_t, src: *const randstate_t) {
let d = unsafe { (*src).seed.d };
let r_ptr = d.cast::<&mut dyn RandGen>().as_ptr();
unsafe {
gen_copy(*r_ptr, dst);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_boxed_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn RandGen>>().as_ptr();
let seed = misc::cast_ptr(seed);
unsafe {
(*r_ptr).seed(&*seed);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_boxed_get(rstate: *mut randstate_t, dest: *mut limb_t, nbits: c_ulong) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn RandGen>>().as_ptr();
unsafe {
gen_bits(&mut **r_ptr, dest, nbits);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_boxed_clear(rstate: *mut randstate_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn RandGen>>().as_ptr();
drop(unsafe { Box::from_raw(r_ptr) });
}
#[cfg(feature = "std")]
unsafe extern "C" fn custom_boxed_iset(dst: *mut randstate_t, src: *const randstate_t) {
let d = unsafe { (*src).seed.d };
let r_ptr = d.cast::<Box<dyn RandGen>>().as_ptr();
unsafe {
gen_copy(&**r_ptr, dst);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn ThreadRandGen>().as_ptr();
let seed = misc::cast_ptr(seed);
unsafe {
(*r_ptr).seed(&*seed);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_get(
rstate: *mut randstate_t,
dest: *mut limb_t,
nbits: c_ulong,
) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn ThreadRandGen>().as_ptr();
unsafe {
thread_gen_bits(*r_ptr, dest, nbits);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_clear(rstate: *mut randstate_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<&mut dyn ThreadRandGen>().as_ptr();
drop(unsafe { Box::from_raw(r_ptr) });
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_iset(dst: *mut randstate_t, src: *const randstate_t) {
let d = unsafe { (*src).seed.d };
let r_ptr = d.cast::<&mut dyn ThreadRandGen>().as_ptr();
unsafe {
thread_gen_copy(*r_ptr, dst);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_boxed_seed(rstate: *mut randstate_t, seed: *const mpz_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn ThreadRandGen>>().as_ptr();
let seed = misc::cast_ptr(seed);
unsafe {
(*r_ptr).seed(&*seed);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_boxed_get(
rstate: *mut randstate_t,
dest: *mut limb_t,
nbits: c_ulong,
) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn ThreadRandGen>>().as_ptr();
unsafe {
thread_gen_bits(&mut **r_ptr, dest, nbits);
}
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_boxed_clear(rstate: *mut randstate_t) {
let d = unsafe { (*rstate).seed.d };
let r_ptr = d.cast::<Box<dyn ThreadRandGen>>().as_ptr();
drop(unsafe { Box::from_raw(r_ptr) });
}
#[cfg(feature = "std")]
unsafe extern "C" fn thread_custom_boxed_iset(dst: *mut randstate_t, src: *const randstate_t) {
let d = unsafe { (*src).seed.d };
let r_ptr = d.cast::<Box<dyn ThreadRandGen>>().as_ptr();
unsafe {
thread_gen_copy(&**r_ptr, dst);
}
}
#[cfg(feature = "std")]
#[cfg(gmp_limb_bits_64)]
unsafe fn gen_bits(gener: &mut dyn RandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 64, nbits % 64);
let limbs = limbs.strict_as::<isize>();
for i in 0..limbs {
let n = u64::from(gener.r#gen()) | (u64::from(gener.r#gen()) << 32);
let n = n.strict_cast();
unsafe {
*dest.offset(i) = n;
}
}
if rest >= 32 {
let mut n = u64::from(gener.r#gen());
if rest > 32 {
let mask = !(!0 << (rest - 32));
n |= u64::from(gener.gen_bits((rest - 32).strict_cast()) & mask) << 32;
}
let n = n.strict_cast();
unsafe {
*dest.offset(limbs) = n;
}
} else if rest > 0 {
let mask = !(!0 << rest);
let n = u64::from(gener.gen_bits(rest.strict_cast()) & mask);
let n = n.strict_cast();
unsafe {
*dest.offset(limbs) = n;
}
}
}
#[cfg(feature = "std")]
#[cfg(gmp_limb_bits_32)]
unsafe fn gen_bits(gener: &mut dyn RandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 32, nbits % 32);
let limbs = limbs.strict_as::<isize>();
for i in 0..limbs {
let val = gener.r#gen().strict_cast();
unsafe {
*dest.offset(i) = val;
}
}
if rest > 0 {
let mask = !(!0 << rest);
let val = (gener.gen_bits(rest.strict_cast()) & mask).strict_cast();
unsafe {
*dest.offset(limbs) = val;
}
}
}
#[cfg(feature = "std")]
unsafe fn gen_copy(gener: &dyn RandGen, dst: *mut randstate_t) {
let (dst_r_ptr, funcs) = if let Some(other) = gener.boxed_clone() {
let b = Box::<Box<dyn RandGen>>::new(other);
let dst_r_ptr = NonNull::<Box<dyn RandGen>>::from(Box::leak(b));
(dst_r_ptr, &CUSTOM_BOXED_FUNCS)
} else {
(NonNull::dangling(), &ABORT_FUNCS)
};
let dst = unsafe { &mut *dst };
*dst = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: dst_r_ptr.cast::<c_void>(),
},
alg: MaybeUninit::uninit(),
algdata: funcs,
};
}
#[cfg(feature = "std")]
#[cfg(gmp_limb_bits_64)]
unsafe fn thread_gen_bits(gener: &mut dyn ThreadRandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 64, nbits % 64);
let limbs = limbs.strict_as::<isize>();
for i in 0..limbs {
let n = u64::from(gener.r#gen()) | (u64::from(gener.r#gen()) << 32);
let n = n.strict_cast();
unsafe {
*dest.offset(i) = n;
}
}
if rest >= 32 {
let mut n = u64::from(gener.r#gen());
if rest > 32 {
let mask = !(!0 << (rest - 32));
n |= u64::from(gener.gen_bits((rest - 32).strict_cast()) & mask) << 32;
}
let n = n.strict_cast();
unsafe {
*dest.offset(limbs) = n;
}
} else if rest > 0 {
let mask = !(!0 << rest);
let n = u64::from(gener.gen_bits(rest.strict_cast()) & mask);
let n = n.strict_cast();
unsafe {
*dest.offset(limbs) = n;
}
}
}
#[cfg(feature = "std")]
#[cfg(gmp_limb_bits_32)]
unsafe fn thread_gen_bits(gener: &mut dyn ThreadRandGen, dest: *mut limb_t, nbits: c_ulong) {
let (limbs, rest) = (nbits / 32, nbits % 32);
let limbs = limbs.strict_as::<isize>();
for i in 0..limbs {
let val = gener.r#gen().strict_cast();
unsafe {
*dest.offset(i) = val;
}
}
if rest > 0 {
let mask = !(!0 << rest);
let val = (gener.gen_bits(rest.strict_cast()) & mask).strict_cast();
unsafe {
*dest.offset(limbs) = val;
}
}
}
#[cfg(feature = "std")]
unsafe fn thread_gen_copy(gener: &dyn ThreadRandGen, dst: *mut randstate_t) {
let (dst_r_ptr, funcs) = if let Some(other) = gener.boxed_clone() {
let b = Box::<Box<dyn ThreadRandGen>>::new(other);
let dst_r_ptr = NonNull::<Box<dyn ThreadRandGen>>::from(Box::leak(b));
(dst_r_ptr, &THREAD_CUSTOM_BOXED_FUNCS)
} else {
(NonNull::dangling(), &ABORT_FUNCS)
};
let dst = unsafe { &mut *dst };
*dst = randstate_t {
seed: randseed_t {
alloc: MaybeUninit::uninit(),
size: MaybeUninit::uninit(),
d: dst_r_ptr.cast::<c_void>(),
},
alg: MaybeUninit::uninit(),
algdata: funcs,
};
}
static ABORT_FUNCS: randfnptr_t = randfnptr_t {
seed: abort_seed,
get: abort_get,
clear: abort_clear,
iset: abort_iset,
};
#[cfg(feature = "std")]
static CUSTOM_FUNCS: randfnptr_t = randfnptr_t {
seed: custom_seed,
get: custom_get,
clear: custom_clear,
iset: custom_iset,
};
#[cfg(feature = "std")]
static CUSTOM_BOXED_FUNCS: randfnptr_t = randfnptr_t {
seed: custom_boxed_seed,
get: custom_boxed_get,
clear: custom_boxed_clear,
iset: custom_boxed_iset,
};
#[cfg(feature = "std")]
static THREAD_CUSTOM_FUNCS: randfnptr_t = randfnptr_t {
seed: thread_custom_seed,
get: thread_custom_get,
clear: thread_custom_clear,
iset: thread_custom_iset,
};
#[cfg(feature = "std")]
static THREAD_CUSTOM_BOXED_FUNCS: randfnptr_t = randfnptr_t {
seed: thread_custom_boxed_seed,
get: thread_custom_boxed_get,
clear: thread_custom_boxed_clear,
iset: 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::RandState;
#[cfg(feature = "std")]
use crate::rand::{RandGen, ThreadRandGen, ThreadRandState};
#[cfg(feature = "std")]
use az::{Az, Cast};
#[cfg(feature = "std")]
use core::ptr;
#[cfg(feature = "std")]
use gmp_mpfr_sys::gmp;
#[cfg(feature = "std")]
struct SimpleGenerator {
seed: u64,
}
#[cfg(feature = "std")]
impl RandGen for SimpleGenerator {
fn r#gen(&mut self) -> u32 {
self.seed = self
.seed
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1);
(self.seed >> 32).cast()
}
#[cfg(feature = "std")]
fn boxed_clone(&self) -> Option<Box<dyn RandGen>> {
let other = SimpleGenerator { seed: self.seed };
let boxed = Box::new(other);
Some(boxed)
}
}
#[cfg(feature = "std")]
#[test]
fn check_custom_clone() {
let mut gener = SimpleGenerator { seed: 1 };
let third2;
{
let mut rand1 = RandState::new_custom(&mut gener);
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(gener));
let mut rand4 = rand3.clone();
let third3 = rand3.bits(32);
let third4 = rand4.bits(32);
assert_eq!(third2, third3);
assert_eq!(third2, third4);
}
#[cfg(feature = "std")]
struct NoCloneGenerator;
#[cfg(feature = "std")]
impl RandGen for NoCloneGenerator {
fn r#gen(&mut self) -> u32 {
0
}
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "`RandGen::boxed_clone` returned `None`")]
fn check_custom_no_clone() {
let mut gener = NoCloneGenerator;
let rand1 = RandState::new_custom(&mut gener);
let _ = rand1.clone();
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "cannot convert custom `RandState` into raw")]
fn check_custom_into_raw() {
let mut gener = NoCloneGenerator;
let rand1 = RandState::new_custom(&mut gener);
let _ = rand1.into_raw();
}
#[cfg(feature = "std")]
struct ThreadSimpleGenerator {
_dummy: *const i32,
seed: u64,
}
#[cfg(feature = "std")]
impl ThreadRandGen for ThreadSimpleGenerator {
fn r#gen(&mut self) -> u32 {
self.seed = self
.seed
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1);
(self.seed >> 32).cast()
}
#[cfg(feature = "std")]
fn boxed_clone(&self) -> Option<Box<dyn ThreadRandGen>> {
let other = ThreadSimpleGenerator {
_dummy: ptr::null(),
seed: self.seed,
};
let boxed = Box::new(other);
Some(boxed)
}
}
#[cfg(feature = "std")]
#[test]
fn thread_check_custom_clone() {
let mut gener = ThreadSimpleGenerator {
_dummy: ptr::null(),
seed: 1,
};
let third2;
{
let mut rand1 = ThreadRandState::new_custom(&mut gener);
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(gener));
let mut rand4 = rand3.clone();
let third3 = rand3.bits(32);
let third4 = rand4.bits(32);
assert_eq!(third2, third3);
assert_eq!(third2, third4);
}
#[cfg(feature = "std")]
struct ThreadNoCloneGenerator;
#[cfg(feature = "std")]
impl ThreadRandGen for ThreadNoCloneGenerator {
fn r#gen(&mut self) -> u32 {
0
}
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "`ThreadRandGen::boxed_clone` returned `None`")]
fn thread_check_custom_no_clone() {
let mut gener = ThreadNoCloneGenerator;
let rand1 = ThreadRandState::new_custom(&mut gener);
let _ = rand1.clone();
}
#[cfg(feature = "std")]
#[test]
#[should_panic(expected = "cannot convert custom `ThreadRandState` into raw")]
fn thread_check_custom_into_raw() {
let mut gener = ThreadNoCloneGenerator;
let rand1 = ThreadRandState::new_custom(&mut gener);
let _ = rand1.into_raw();
}
#[cfg(feature = "std")]
#[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) }.az::<u32>(),
check.bits(32)
);
let mut raw = state.into_raw();
assert_eq!(
unsafe { gmp::urandomb_ui(&mut raw, 32) }.az::<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());
}
}