Skip to content

Commit

Permalink
Add back serde to IsacRng and Isaac64Rng
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Apr 3, 2018
1 parent 610e975 commit 58fd61d
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 81 deletions.
50 changes: 13 additions & 37 deletions src/prng/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use core::{fmt, slice};
use core::num::Wrapping as w;
use rand_core::{BlockRngCore, RngCore, SeedableRng, Error, le};
use rand_core::impls::BlockRng;
use prng::isaac_array::IsaacArray;

#[allow(non_camel_case_types)]
type w32 = w<u32>;
Expand Down Expand Up @@ -86,6 +87,7 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
///
/// [`Hc128Rng`]: hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct IsaacRng(BlockRng<IsaacCore>);

impl RngCore for IsaacRng {
Expand Down Expand Up @@ -145,14 +147,16 @@ impl IsaacRng {
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
core: IsaacCore::init(key, 1),
results: IsaacArray([0; RAND_SIZE]),
results: IsaacArray::default(),
index: RAND_SIZE, // generate on first use
})
}
}

#[derive(Clone)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct IsaacCore {
#[cfg_attr(feature="serde-1",serde(with="super::isaac_array::isaac_array_serde"))]
mem: [w32; RAND_SIZE],
a: w32,
b: w32,
Expand All @@ -166,37 +170,9 @@ impl fmt::Debug for IsaacCore {
}
}

// Terrible workaround because arrays with more than 32 elements do not
// implement `AsRef` (or any other traits for that matter)
#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct IsaacArray([u32; RAND_SIZE]);
impl ::core::convert::AsRef<[u32]> for IsaacArray {
#[inline(always)]
fn as_ref(&self) -> &[u32] {
&self.0[..]
}
}
impl ::core::ops::Deref for IsaacArray {
type Target = [u32; RAND_SIZE];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for IsaacArray {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [u32; RAND_SIZE] {
&mut self.0
}
}
impl ::core::default::Default for IsaacArray {
fn default() -> IsaacArray { IsaacArray([0u32; RAND_SIZE]) }
}

impl BlockRngCore for IsaacCore {
type Item = u32;
type Results = IsaacArray;
type Results = IsaacArray<Self::Item>;

/// Refills the output buffer (`results`)
/// See also the pseudocode desciption of the algorithm at the top of this
Expand All @@ -217,7 +193,7 @@ impl BlockRngCore for IsaacCore {
/// from `results` in reverse. We read them in the normal direction, to
/// make `fill_bytes` a memcopy. To maintain compatibility we fill in
/// reverse.
fn generate(&mut self, results: &mut IsaacArray) {
fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
self.c += w(1);
// abbreviations
let mut a = self.a;
Expand Down Expand Up @@ -493,17 +469,17 @@ mod test {
let mut read = BufReader::new(&buf[..]);
let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize");

assert_eq!(rng.index, deserialized.index);
assert_eq!(rng.0.index, deserialized.0.index);
/* Can't assert directly because of the array size */
for (orig,deser) in rng.rsl.iter().zip(deserialized.rsl.iter()) {
for (orig,deser) in rng.0.results.iter().zip(deserialized.0.results.iter()) {
assert_eq!(orig, deser);
}
for (orig,deser) in rng.mem.iter().zip(deserialized.mem.iter()) {
for (orig,deser) in rng.0.core.mem.iter().zip(deserialized.0.core.mem.iter()) {
assert_eq!(orig, deser);
}
assert_eq!(rng.a, deserialized.a);
assert_eq!(rng.b, deserialized.b);
assert_eq!(rng.c, deserialized.c);
assert_eq!(rng.0.core.a, deserialized.0.core.a);
assert_eq!(rng.0.core.b, deserialized.0.core.b);
assert_eq!(rng.0.core.c, deserialized.0.core.c);

for _ in 0..16 {
assert_eq!(rng.next_u64(), deserialized.next_u64());
Expand Down
52 changes: 14 additions & 38 deletions src/prng/isaac64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use core::{fmt, slice};
use core::num::Wrapping as w;
use rand_core::{BlockRngCore, RngCore, SeedableRng, Error, le};
use rand_core::impls::BlockRng64;
use prng::isaac_array::IsaacArray;

#[allow(non_camel_case_types)]
type w64 = w<u64>;
Expand Down Expand Up @@ -76,6 +77,7 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html
/// [`Hc128Rng`]: hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct Isaac64Rng(BlockRng64<Isaac64Core>);

impl RngCore for Isaac64Rng {
Expand Down Expand Up @@ -134,15 +136,17 @@ impl Isaac64Rng {
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
core: Isaac64Core::init(key, 1),
results: Isaac64Array([0; RAND_SIZE]),
results: IsaacArray::default(),
index: RAND_SIZE, // generate on first use
half_used: false,
})
}
}

#[derive(Clone)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct Isaac64Core {
#[cfg_attr(feature="serde-1",serde(with="super::isaac_array::isaac_array_serde"))]
mem: [w64; RAND_SIZE],
a: w64,
b: w64,
Expand All @@ -156,37 +160,9 @@ impl fmt::Debug for Isaac64Core {
}
}

// Terrible workaround because arrays with more than 32 elements do not
// implement `AsRef` (or any other traits for that matter)
#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct Isaac64Array([u64; RAND_SIZE]);
impl ::core::convert::AsRef<[u64]> for Isaac64Array {
#[inline(always)]
fn as_ref(&self) -> &[u64] {
&self.0[..]
}
}
impl ::core::ops::Deref for Isaac64Array {
type Target = [u64; RAND_SIZE];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for Isaac64Array {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [u64; RAND_SIZE] {
&mut self.0
}
}
impl ::core::default::Default for Isaac64Array {
fn default() -> Isaac64Array { Isaac64Array([0u64; RAND_SIZE]) }
}

impl BlockRngCore for Isaac64Core {
type Item = u64;
type Results = Isaac64Array;
type Results = IsaacArray<Self::Item>;

/// Refills the output buffer (`results`)
/// See also the pseudocode desciption of the algorithm at the top of this
Expand All @@ -207,7 +183,7 @@ impl BlockRngCore for Isaac64Core {
/// from `results` in reverse. We read them in the normal direction, to
/// make `fill_bytes` a memcopy. To maintain compatibility we fill in
/// reverse.
fn generate(&mut self, results: &mut Isaac64Array) {
fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
self.c += w(1);
// abbreviations
let mut a = self.a;
Expand Down Expand Up @@ -486,18 +462,18 @@ mod test {
let mut read = BufReader::new(&buf[..]);
let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize");

assert_eq!(rng.index, deserialized.index);
assert_eq!(rng.half_used, deserialized.half_used);
assert_eq!(rng.0.index, deserialized.0.index);
assert_eq!(rng.0.half_used, deserialized.0.half_used);
/* Can't assert directly because of the array size */
for (orig,deser) in rng.rsl.iter().zip(deserialized.rsl.iter()) {
for (orig,deser) in rng.0.results.iter().zip(deserialized.0.results.iter()) {
assert_eq!(orig, deser);
}
for (orig,deser) in rng.mem.iter().zip(deserialized.mem.iter()) {
for (orig,deser) in rng.0.core.mem.iter().zip(deserialized.0.core.mem.iter()) {
assert_eq!(orig, deser);
}
assert_eq!(rng.a, deserialized.a);
assert_eq!(rng.b, deserialized.b);
assert_eq!(rng.c, deserialized.c);
assert_eq!(rng.0.core.a, deserialized.0.core.a);
assert_eq!(rng.0.core.b, deserialized.0.core.b);
assert_eq!(rng.0.core.c, deserialized.0.core.c);

for _ in 0..16 {
assert_eq!(rng.next_u64(), deserialized.next_u64());
Expand Down
59 changes: 55 additions & 4 deletions src/prng/isaac_serde.rs → src/prng/isaac_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,60 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ISAAC serde helper functions.
//! ISAAC helper functions for 256-element arrays.
pub(super) mod rand_size_serde {
// Terrible workaround because arrays with more than 32 elements do not
// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other
// traits for that matter.

#[cfg(feature="serde-1")] use serde::{Serialize, Deserialize};

const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;


#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct IsaacArray<T> where T: Default + Copy {
#[cfg_attr(feature="serde-1",serde(with="isaac_array_serde"))]
#[cfg_attr(feature="serde-1", serde(bound(
serialize = "T: Serialize",
deserialize = "T: Deserialize<'de>")))]
inner: [T; RAND_SIZE]
}

impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> where T: Default + Copy {
#[inline(always)]
fn as_ref(&self) -> &[T] {
&self.inner[..]
}
}

impl<T> ::core::ops::Deref for IsaacArray<T> where T: Default + Copy {
type Target = [T; RAND_SIZE];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<T> ::core::ops::DerefMut for IsaacArray<T> where T: Default + Copy {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] {
&mut self.inner
}
}

impl<T> ::core::default::Default for IsaacArray<T> where T: Default + Copy {
fn default() -> IsaacArray<T> {
IsaacArray { inner: [T::default(); RAND_SIZE] }
}
}


#[cfg(feature="serde-1")]
pub(super) mod isaac_array_serde {
const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

Expand All @@ -20,10 +71,10 @@ pub(super) mod rand_size_serde {

use core::fmt;

pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer
S: Serializer
{
use serde::ser::SerializeTuple;

Expand Down
3 changes: 1 addition & 2 deletions src/prng/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ mod isaac;
mod isaac64;
mod xorshift;

#[cfg(feature="serde-1")]
mod isaac_serde;
mod isaac_array;

#[doc(inline)] pub use self::chacha::ChaChaRng;
#[doc(inline)] pub use self::hc128::Hc128Rng;
Expand Down

0 comments on commit 58fd61d

Please sign in to comment.