use core::convert::AsRef;
use core::fmt;
use {RngCore, CryptoRng, SeedableRng, Error};
use impls::{fill_via_u32_chunks, fill_via_u64_chunks};
pub trait BlockRngCore {
type Item;
type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default;
fn generate(&mut self, results: &mut Self::Results);
}
#[derive(Clone)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
pub struct BlockRng<R: BlockRngCore + ?Sized> {
results: R::Results,
index: usize,
pub core: R,
}
impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BlockRng")
.field("core", &self.core)
.field("result_len", &self.results.as_ref().len())
.field("index", &self.index)
.finish()
}
}
impl<R: BlockRngCore> BlockRng<R> {
pub fn new(core: R) -> BlockRng<R>{
let results_empty = R::Results::default();
BlockRng {
core,
index: results_empty.as_ref().len(),
results: results_empty,
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn reset(&mut self) {
self.index = self.results.as_ref().len();
}
pub fn generate_and_set(&mut self, index: usize) {
assert!(index < self.results.as_ref().len());
self.core.generate(&mut self.results);
self.index = index;
}
}
impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R>
where <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
{
#[inline(always)]
fn next_u32(&mut self) -> u32 {
if self.index >= self.results.as_ref().len() {
self.generate_and_set(0);
}
let value = self.results.as_ref()[self.index];
self.index += 1;
value
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
let read_u64 = |results: &[u32], index| {
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
unsafe { *(&results[index] as *const u32 as *const u64) }
} else {
let x = u64::from(results[index]);
let y = u64::from(results[index + 1]);
(y << 32) | x
}
};
let len = self.results.as_ref().len();
let index = self.index;
if index < len-1 {
self.index += 2;
read_u64(self.results.as_ref(), index)
} else if index >= len {
self.generate_and_set(2);
read_u64(self.results.as_ref(), 0)
} else {
let x = u64::from(self.results.as_ref()[len-1]);
self.generate_and_set(1);
let y = u64::from(self.results.as_ref()[0]);
(y << 32) | x
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut filled = 0;
if self.index < self.results.as_ref().len() {
let (consumed_u32, filled_u8) =
fill_via_u32_chunks(&self.results.as_ref()[self.index..],
dest);
self.index += consumed_u32;
filled += filled_u8;
}
let len_remainder =
(dest.len() - filled) % (self.results.as_ref().len() * 4);
let end_direct = dest.len() - len_remainder;
while filled < end_direct {
let dest_u32: &mut R::Results = unsafe {
&mut *(dest[filled..].as_mut_ptr() as
*mut <R as BlockRngCore>::Results)
};
self.core.generate(dest_u32);
filled += self.results.as_ref().len() * 4;
self.index = self.results.as_ref().len();
}
if len_remainder > 0 {
self.core.generate(&mut self.results);
let (consumed_u32, _) =
fill_via_u32_chunks(self.results.as_ref(),
&mut dest[filled..]);
self.index = consumed_u32;
}
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
while read_len < dest.len() {
if self.index >= self.results.as_ref().len() {
self.generate_and_set(0);
}
let (consumed_u32, filled_u8) =
fill_via_u32_chunks(&self.results.as_ref()[self.index..],
&mut dest[read_len..]);
self.index += consumed_u32;
read_len += filled_u8;
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
type Seed = R::Seed;
fn from_seed(seed: Self::Seed) -> Self {
Self::new(R::from_seed(seed))
}
fn seed_from_u64(seed: u64) -> Self {
Self::new(R::seed_from_u64(seed))
}
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
Ok(Self::new(R::from_rng(rng)?))
}
}
#[derive(Clone)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
pub struct BlockRng64<R: BlockRngCore + ?Sized> {
results: R::Results,
index: usize,
half_used: bool, pub core: R,
}
impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BlockRng64")
.field("core", &self.core)
.field("result_len", &self.results.as_ref().len())
.field("index", &self.index)
.field("half_used", &self.half_used)
.finish()
}
}
impl<R: BlockRngCore> BlockRng64<R> {
pub fn new(core: R) -> BlockRng64<R>{
let results_empty = R::Results::default();
BlockRng64 {
core,
index: results_empty.as_ref().len(),
half_used: false,
results: results_empty,
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn reset(&mut self) {
self.index = self.results.as_ref().len();
self.half_used = false;
}
pub fn generate_and_set(&mut self, index: usize) {
assert!(index < self.results.as_ref().len());
self.core.generate(&mut self.results);
self.index = index;
self.half_used = false;
}
}
impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R>
where <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]>
{
#[inline(always)]
fn next_u32(&mut self) -> u32 {
let mut index = self.index * 2 - self.half_used as usize;
if index >= self.results.as_ref().len() * 2 {
self.core.generate(&mut self.results);
self.index = 0;
self.half_used = false;
index = 0;
}
self.half_used = !self.half_used;
self.index += self.half_used as usize;
unsafe {
let results =
&*(self.results.as_ref() as *const [u64] as *const [u32]);
if cfg!(target_endian = "little") {
*results.get_unchecked(index)
} else {
*results.get_unchecked(index ^ 1)
}
}
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
if self.index >= self.results.as_ref().len() {
self.core.generate(&mut self.results);
self.index = 0;
}
let value = self.results.as_ref()[self.index];
self.index += 1;
self.half_used = false;
value
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut filled = 0;
self.half_used = false;
if self.index < self.results.as_ref().len() {
let (consumed_u64, filled_u8) =
fill_via_u64_chunks(&self.results.as_ref()[self.index..],
dest);
self.index += consumed_u64;
filled += filled_u8;
}
let len_remainder =
(dest.len() - filled) % (self.results.as_ref().len() * 8);
let end_direct = dest.len() - len_remainder;
while filled < end_direct {
let dest_u64: &mut R::Results = unsafe {
::core::mem::transmute(dest[filled..].as_mut_ptr())
};
self.core.generate(dest_u64);
filled += self.results.as_ref().len() * 8;
self.index = self.results.as_ref().len();
}
if len_remainder > 0 {
self.core.generate(&mut self.results);
let (consumed_u64, _) =
fill_via_u64_chunks(&mut self.results.as_ref(),
&mut dest[filled..]);
self.index = consumed_u64;
}
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
self.half_used = false;
while read_len < dest.len() {
if self.index as usize >= self.results.as_ref().len() {
self.core.generate(&mut self.results);
self.index = 0;
}
let (consumed_u64, filled_u8) =
fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..],
&mut dest[read_len..]);
self.index += consumed_u64;
read_len += filled_u8;
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(self.fill_bytes(dest))
}
}
impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
type Seed = R::Seed;
fn from_seed(seed: Self::Seed) -> Self {
Self::new(R::from_seed(seed))
}
fn seed_from_u64(seed: u64) -> Self {
Self::new(R::seed_from_u64(seed))
}
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
Ok(Self::new(R::from_rng(rng)?))
}
}
impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {}