From b55f47e8385e3fed408080e502d2c0308446c14b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 13 Apr 2018 09:58:03 +0200 Subject: [PATCH 1/2] Update rand_core CHANGELOG and README --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- rand_core/CHANGELOG.md | 2 +- rand_core/README.md | 3 +++ rand_core/src/lib.rs | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9a0a2d96a..39785830a9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ You may also find the [Update Guide](UPDATING.md) useful. - Add `Error` and `ErrorKind`. (#225) - Add `CryptoRng` marker trait. (#273) - Add `BlockRngCore` trait. (#281) -- Add `BlockRng` wrapper to help implementations. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) - Revise the `SeedableRng` trait. (#233) - Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) - Add `RngCore::try_fill_bytes`. (#225) diff --git a/Cargo.toml b/Cargo.toml index 27b0aadc3d9..71d335cae92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ serde1 = ["serde", "serde_derive", "rand_core/serde1"] # enables serialization f members = ["rand_core"] [dependencies] -rand_core = { path="rand_core", default-features = false } +rand_core = { path = "rand_core", version = "0.1.0-pre.0", default-features = false } log = { version = "0.4", optional = true } serde = { version = "1", optional = true } serde_derive = { version = "1", optional = true } diff --git a/rand_core/CHANGELOG.md b/rand_core/CHANGELOG.md index e52cfcbecb8..01633311648 100644 --- a/rand_core/CHANGELOG.md +++ b/rand_core/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `Error` and `ErrorKind`. (#225) - Add `CryptoRng` marker trait. (#273) - Add `BlockRngCore` trait. (#281) -- Add `BlockRng` wrapper to help implemtations. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) - Revise the `SeedableRng` trait. (#233) - Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) - Add `RngCore::try_fill_bytes`. (#225) diff --git a/rand_core/README.md b/rand_core/README.md index 7e3af1e2a7b..29492224ca7 100644 --- a/rand_core/README.md +++ b/rand_core/README.md @@ -50,6 +50,9 @@ Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596), unioned across the whole dependency tree, any crate using `rand` with its default features will also enable `std` support in `rand_core`. +The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG +implementations that use the `BlockRng` or `BlockRng64` wrappers. + # License diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 61dc4cb9aed..924d44efa90 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -35,7 +35,7 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://docs.rs/rand_core/0.1")] + html_root_url = "https://docs.rs/rand_core/0.1.0-pre.0")] #![deny(missing_debug_implementations)] From 86493ca4bee20d2b9945c8cfd7345f8e0a9125f8 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 13 Apr 2018 13:57:22 +0200 Subject: [PATCH 2/2] Optimize `fill_bytes_via` --- rand_core/src/impls.rs | 57 +++++++++++++++++++++--------------------- rand_core/src/lib.rs | 5 ++-- src/jitter.rs | 2 +- src/mock.rs | 2 +- src/prng/xorshift.rs | 4 ++- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs index 645dc8f990b..530a2ed7d65 100644 --- a/rand_core/src/impls.rs +++ b/rand_core/src/impls.rs @@ -37,35 +37,34 @@ pub fn next_u64_via_u32(rng: &mut R) -> u64 { (y << 32) | x } -macro_rules! fill_bytes_via { - ($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{ - let mut left = $dest; - while left.len() >= $BYTES { - let (l, r) = {left}.split_at_mut($BYTES); - left = r; - let chunk: [u8; $BYTES] = unsafe { - transmute($rng.$next_u().to_le()) - }; - l.copy_from_slice(&chunk); - } - let n = left.len(); - if n > 0 { - let chunk: [u8; $BYTES] = unsafe { - transmute($rng.$next_u().to_le()) - }; - left.copy_from_slice(&chunk[..n]); - } - }} -} - -/// Implement `fill_bytes` via `next_u32`, little-endian order. -pub fn fill_bytes_via_u32(rng: &mut R, dest: &mut [u8]) { - fill_bytes_via!(rng, next_u32, 4, dest) -} - -/// Implement `fill_bytes` via `next_u64`, little-endian order. -pub fn fill_bytes_via_u64(rng: &mut R, dest: &mut [u8]) { - fill_bytes_via!(rng, next_u64, 8, dest) +/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. +/// +/// The fastest way to fill a slice is usually to work as long as possible with +/// integers. That is why this method mostly uses `next_u64`, and only when +/// there are 4 or less bytes remaining at the end of the slice it uses +/// `next_u32` once. +pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 4 { + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } else if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(rng.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } } macro_rules! impl_uint_from_fill { diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 924d44efa90..7ac0686debb 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -121,7 +121,7 @@ pub mod le; /// } /// /// fn fill_bytes(&mut self, dest: &mut [u8]) { -/// impls::fill_bytes_via_u64(self, dest) +/// impls::fill_bytes_via_next(self, dest) /// } /// /// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { @@ -160,8 +160,7 @@ pub trait RngCore { /// /// RNGs must implement at least one method from this trait directly. In /// the case this method is not implemented directly, it can be implemented - /// [via `next_u32`](../rand_core/impls/fn.fill_bytes_via_u32.html) or - /// [via `next_u64`](../rand_core/impls/fn.fill_bytes_via_u64.html) or + /// [via `next_u*`](../rand_core/impls/fn.fill_bytes_via_next.html) or /// via `try_fill_bytes`; if this generator can fail the implementation /// must choose how best to handle errors here (e.g. panic with a /// descriptive message or log a warning and retry a few times). diff --git a/src/jitter.rs b/src/jitter.rs index 719afa3ae7a..5811479e646 100644 --- a/src/jitter.rs +++ b/src/jitter.rs @@ -804,7 +804,7 @@ impl RngCore for JitterRng { // // This is done especially for wrappers that implement `next_u32` // themselves via `fill_bytes`. - impls::fill_bytes_via_u32(self, dest) + impls::fill_bytes_via_next(self, dest) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { diff --git a/src/mock.rs b/src/mock.rs index 5c73594fa08..090258ef8b2 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -52,7 +52,7 @@ impl RngCore for StepRng { } fn fill_bytes(&mut self, dest: &mut [u8]) { - impls::fill_bytes_via_u64(self, dest); + impls::fill_bytes_via_next(self, dest); } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { diff --git a/src/prng/xorshift.rs b/src/prng/xorshift.rs index 9f7a3c88bb5..9fac6e33d51 100644 --- a/src/prng/xorshift.rs +++ b/src/prng/xorshift.rs @@ -71,12 +71,14 @@ impl RngCore for XorShiftRng { self.w.0 } + #[inline] fn next_u64(&mut self) -> u64 { impls::next_u64_via_u32(self) } + #[inline] fn fill_bytes(&mut self, dest: &mut [u8]) { - impls::fill_bytes_via_u32(self, dest) + impls::fill_bytes_via_next(self, dest) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {