Skip to content

Commit 979306d

Browse files
authored
Merge pull request #397 from pitdicker/rand_core_0.1
Optimize `fill_bytes_via_*` and prepare rand_core 0.1
2 parents 2d3fb0c + 86493ca commit 979306d

File tree

9 files changed

+42
-39
lines changed

9 files changed

+42
-39
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ You may also find the [Update Guide](UPDATING.md) useful.
3737
- Add `Error` and `ErrorKind`. (#225)
3838
- Add `CryptoRng` marker trait. (#273)
3939
- Add `BlockRngCore` trait. (#281)
40-
- Add `BlockRng` wrapper to help implementations. (#281)
40+
- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
4141
- Revise the `SeedableRng` trait. (#233)
4242
- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
4343
- Add `RngCore::try_fill_bytes`. (#225)

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ serde1 = ["serde", "serde_derive", "rand_core/serde1"] # enables serialization f
2929
members = ["rand_core"]
3030

3131
[dependencies]
32-
rand_core = { path="rand_core", default-features = false }
32+
rand_core = { path = "rand_core", version = "0.1.0-pre.0", default-features = false }
3333
log = { version = "0.4", optional = true }
3434
serde = { version = "1", optional = true }
3535
serde_derive = { version = "1", optional = true }

rand_core/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Add `Error` and `ErrorKind`. (#225)
1313
- Add `CryptoRng` marker trait. (#273)
1414
- Add `BlockRngCore` trait. (#281)
15-
- Add `BlockRng` wrapper to help implemtations. (#281)
15+
- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
1616
- Revise the `SeedableRng` trait. (#233)
1717
- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
1818
- Add `RngCore::try_fill_bytes`. (#225)

rand_core/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596),
5050
unioned across the whole dependency tree, any crate using `rand` with its
5151
default features will also enable `std` support in `rand_core`.
5252

53+
The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG
54+
implementations that use the `BlockRng` or `BlockRng64` wrappers.
55+
5356

5457
# License
5558

rand_core/src/impls.rs

+28-29
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,34 @@ pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
3737
(y << 32) | x
3838
}
3939

40-
macro_rules! fill_bytes_via {
41-
($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
42-
let mut left = $dest;
43-
while left.len() >= $BYTES {
44-
let (l, r) = {left}.split_at_mut($BYTES);
45-
left = r;
46-
let chunk: [u8; $BYTES] = unsafe {
47-
transmute($rng.$next_u().to_le())
48-
};
49-
l.copy_from_slice(&chunk);
50-
}
51-
let n = left.len();
52-
if n > 0 {
53-
let chunk: [u8; $BYTES] = unsafe {
54-
transmute($rng.$next_u().to_le())
55-
};
56-
left.copy_from_slice(&chunk[..n]);
57-
}
58-
}}
59-
}
60-
61-
/// Implement `fill_bytes` via `next_u32`, little-endian order.
62-
pub fn fill_bytes_via_u32<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
63-
fill_bytes_via!(rng, next_u32, 4, dest)
64-
}
65-
66-
/// Implement `fill_bytes` via `next_u64`, little-endian order.
67-
pub fn fill_bytes_via_u64<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
68-
fill_bytes_via!(rng, next_u64, 8, dest)
40+
/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
41+
///
42+
/// The fastest way to fill a slice is usually to work as long as possible with
43+
/// integers. That is why this method mostly uses `next_u64`, and only when
44+
/// there are 4 or less bytes remaining at the end of the slice it uses
45+
/// `next_u32` once.
46+
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
47+
let mut left = dest;
48+
while left.len() >= 8 {
49+
let (l, r) = {left}.split_at_mut(8);
50+
left = r;
51+
let chunk: [u8; 8] = unsafe {
52+
transmute(rng.next_u64().to_le())
53+
};
54+
l.copy_from_slice(&chunk);
55+
}
56+
let n = left.len();
57+
if n > 4 {
58+
let chunk: [u8; 8] = unsafe {
59+
transmute(rng.next_u64().to_le())
60+
};
61+
left.copy_from_slice(&chunk[..n]);
62+
} else if n > 0 {
63+
let chunk: [u8; 4] = unsafe {
64+
transmute(rng.next_u32().to_le())
65+
};
66+
left.copy_from_slice(&chunk[..n]);
67+
}
6968
}
7069

7170
macro_rules! impl_uint_from_fill {

rand_core/src/lib.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
3636
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
3737
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
38-
html_root_url = "https://docs.rs/rand_core/0.1")]
38+
html_root_url = "https://docs.rs/rand_core/0.1.0-pre.0")]
3939

4040
#![deny(missing_debug_implementations)]
4141

@@ -121,7 +121,7 @@ pub mod le;
121121
/// }
122122
///
123123
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
124-
/// impls::fill_bytes_via_u64(self, dest)
124+
/// impls::fill_bytes_via_next(self, dest)
125125
/// }
126126
///
127127
/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
@@ -160,8 +160,7 @@ pub trait RngCore {
160160
///
161161
/// RNGs must implement at least one method from this trait directly. In
162162
/// the case this method is not implemented directly, it can be implemented
163-
/// [via `next_u32`](../rand_core/impls/fn.fill_bytes_via_u32.html) or
164-
/// [via `next_u64`](../rand_core/impls/fn.fill_bytes_via_u64.html) or
163+
/// [via `next_u*`](../rand_core/impls/fn.fill_bytes_via_next.html) or
165164
/// via `try_fill_bytes`; if this generator can fail the implementation
166165
/// must choose how best to handle errors here (e.g. panic with a
167166
/// descriptive message or log a warning and retry a few times).

src/jitter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ impl RngCore for JitterRng {
804804
//
805805
// This is done especially for wrappers that implement `next_u32`
806806
// themselves via `fill_bytes`.
807-
impls::fill_bytes_via_u32(self, dest)
807+
impls::fill_bytes_via_next(self, dest)
808808
}
809809

810810
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

src/mock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl RngCore for StepRng {
5252
}
5353

5454
fn fill_bytes(&mut self, dest: &mut [u8]) {
55-
impls::fill_bytes_via_u64(self, dest);
55+
impls::fill_bytes_via_next(self, dest);
5656
}
5757

5858
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

src/prng/xorshift.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ impl RngCore for XorShiftRng {
7171
self.w.0
7272
}
7373

74+
#[inline]
7475
fn next_u64(&mut self) -> u64 {
7576
impls::next_u64_via_u32(self)
7677
}
7778

79+
#[inline]
7880
fn fill_bytes(&mut self, dest: &mut [u8]) {
79-
impls::fill_bytes_via_u32(self, dest)
81+
impls::fill_bytes_via_next(self, dest)
8082
}
8183

8284
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {

0 commit comments

Comments
 (0)