-
Notifications
You must be signed in to change notification settings - Fork 115
Impl rand_core::RngCore & support all integers in Rng #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,8 @@ use crate::time::Hertz; | |
|
||
#[derive(Debug)] | ||
pub enum ErrorKind { | ||
ClockError, | ||
SeedError, | ||
ClockError = 0, | ||
SeedError = 1, | ||
} | ||
|
||
trait KerClk { | ||
|
@@ -131,8 +131,112 @@ macro_rules! rng_core { | |
}; | ||
} | ||
|
||
rng_core!(u32, u16, u8); | ||
// Only for types larger than 32 bits | ||
macro_rules! rng_core_large { | ||
($($type:ty),+) => { | ||
$( | ||
impl RngCore<$type> for Rng { | ||
fn gen(&mut self) -> Result<$type, ErrorKind> { | ||
const WORDS: usize = mem::size_of::<$type>() / mem::size_of::<u32>(); | ||
let mut res: $type = 0; | ||
|
||
for i in 0..WORDS { | ||
res |= (self.value()? as $type) << (i * (mem::size_of::<u32>() * 8)) | ||
} | ||
|
||
Ok(res) | ||
} | ||
|
||
fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> { | ||
let len = dest.len() * (mem::size_of::<$type>() / mem::size_of::<u32>()); | ||
let ptr = dest.as_mut_ptr() as *mut u32; | ||
let slice_u32 = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is alignment an issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think so. u64/u128 is 8-byte aligned which would be valid for 4-byte aligned values as well. https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh right, I hadn't seen the distinction between |
||
self.fill(slice_u32) | ||
} | ||
} | ||
)+ | ||
}; | ||
} | ||
|
||
macro_rules! rng_core_transmute { | ||
($($type:ty = $from:ty),+) => { | ||
$( | ||
impl RngCore<$type> for Rng { | ||
fn gen(&mut self) -> Result<$type, ErrorKind> { | ||
let num = <Self as RngCore<$from>>::gen(self)?; | ||
Ok(unsafe { mem::transmute::<$from, $type>(num) }) | ||
} | ||
|
||
// Test host may have > 32-bit types, which we don't consider. | ||
fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> { | ||
let unsigned_slice = unsafe { mem::transmute::<&mut [$type], &mut [$from]>(dest) }; | ||
<Self as RngCore<$from>>::fill(self, unsigned_slice) | ||
} | ||
} | ||
)+ | ||
}; | ||
} | ||
|
||
rng_core!(u8, u16, u32); | ||
|
||
// Alignment of these types must be a multiple of mem::align_of::<32>() | ||
rng_core_large!(u64, u128); | ||
|
||
// A and B must have the same alignment | ||
// rng_core_transmute!(A = B) | ||
// assert!(mem::align_of::<A>() == mem::align_of::<B>()) | ||
rng_core_transmute!( | ||
i8 = u8, | ||
i16 = u16, | ||
i32 = u32, | ||
i64 = u64, | ||
i128 = u128, | ||
isize = usize | ||
); | ||
|
||
// If usize is 32 bits, use the rng_core! impl | ||
#[cfg(target_pointer_width = "32")] | ||
rng_core!(usize); | ||
|
||
// If usize is 64 bits, use the rng_core_large! impl | ||
#[cfg(target_pointer_width = "64")] | ||
rng_core_large!(usize); | ||
|
||
// rand_core | ||
#[cfg(feature = "rand")] | ||
impl rand_core::RngCore for Rng { | ||
/// Generate a random u32 | ||
/// Panics if RNG fails. | ||
fn next_u32(&mut self) -> u32 { | ||
self.gen().unwrap() | ||
} | ||
|
||
/// Generate a random u64 | ||
/// Panics if RNG fails. | ||
fn next_u64(&mut self) -> u64 { | ||
self.gen().unwrap() | ||
} | ||
|
||
/// Fill a slice with random data. | ||
/// Panics if RNG fails. | ||
fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
self.fill(dest).unwrap() | ||
} | ||
|
||
/// Try to fill a slice with random data. Return an error if RNG fails. | ||
fn try_fill_bytes( | ||
&mut self, | ||
dest: &mut [u8], | ||
) -> Result<(), rand_core::Error> { | ||
self.fill(dest).map_err(|e| { | ||
core::num::NonZeroU32::new( | ||
rand_core::Error::CUSTOM_START + e as u32, | ||
) | ||
// This should never fail as long as no enum variant is equal to 0 | ||
.expect("Internal hal error") | ||
.into() | ||
}) | ||
} | ||
} | ||
|
||
#[cfg(feature = "rand")] | ||
impl rand_core::CryptoRng for Rng {} |
Uh oh!
There was an error while loading. Please reload this page.