Upgrade rust/crates/rand_core to 0.6.0
Test: make
Change-Id: I8f507d4c59ea4b12ecb1dfbcc4e453bddda61698
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index ecc9adc..0db4f9b 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "d877ed528248b52d947e0484364a4e1ae59ca502"
+ "sha1": "98e220c30234370fb04ba928799ebd9727fc049a"
}
}
diff --git a/Android.bp b/Android.bp
index bf36d3a..c5526ed 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,5 +45,5 @@
// dependent_library ["feature_list"]
// cfg-if-0.1.10
-// getrandom-0.1.14 "std"
-// libc-0.2.72
+// getrandom-0.2.0 "std"
+// libc-0.2.81
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dfdd692..63a8bb8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,20 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.6.0] - 2020-12-08
+### Breaking changes
+- Bump MSRV to 1.36, various code improvements (#1011)
+- Update to getrandom v0.2 (#1041)
+- Fix: `next_u32_via_fill` and `next_u64_via_fill` now use LE as documented (#1061)
+
+### Other
+- Reduce usage of `unsafe` (#962, #963, #1011)
+- Annotate feature-gates in documentation (#1019)
+- Document available error codes (#1061)
+- Various documentation tweaks
+- Fix some clippy warnings (#1036)
+- Apply rustfmt (#926)
+
## [0.5.1] - 2019-08-28
- `OsRng` added to `rand_core` (#863)
- `Error::INTERNAL_START` and `Error::CUSTOM_START` constants (#864)
diff --git a/Cargo.toml b/Cargo.toml
index 572276e..508f993 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "rand_core"
-version = "0.5.1"
+version = "0.6.0"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
description = "Core random number generator traits and tools for implementation.\n"
homepage = "https://crates.io/crates/rand_core"
@@ -23,8 +23,11 @@
categories = ["algorithms", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-random/rand"
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "doc_cfg"]
[dependencies.getrandom]
-version = "0.1"
+version = "0.2"
optional = true
[dependencies.serde]
@@ -36,8 +39,3 @@
alloc = []
serde1 = ["serde"]
std = ["alloc", "getrandom", "getrandom/std"]
-[badges.appveyor]
-repository = "rust-random/rand"
-
-[badges.travis-ci]
-repository = "rust-random/rand"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index e52af5f..c383b31 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "rand_core"
-version = "0.5.1"
+version = "0.6.0"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT OR Apache-2.0"
readme = "README.md"
@@ -14,10 +14,6 @@
categories = ["algorithms", "no-std"]
edition = "2018"
-[badges]
-travis-ci = { repository = "rust-random/rand" }
-appveyor = { repository = "rust-random/rand" }
-
[features]
std = ["alloc", "getrandom", "getrandom/std"] # use std library; should be default but for above bug
alloc = [] # enables Vec and Box support without std
@@ -25,4 +21,10 @@
[dependencies]
serde = { version = "1", features = ["derive"], optional = true }
-getrandom = { version = "0.1", optional = true }
+getrandom = { version = "0.2", optional = true }
+
+[package.metadata.docs.rs]
+# To build locally:
+# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open
+all-features = true
+rustdoc-args = ["--cfg", "doc_cfg"]
diff --git a/METADATA b/METADATA
index 833f5dc..37999a5 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/rand_core/rand_core-0.5.1.crate"
+ value: "https://static.crates.io/crates/rand_core/rand_core-0.6.0.crate"
}
- version: "0.5.1"
+ version: "0.6.0"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 6
- day: 18
+ month: 12
+ day: 15
}
}
diff --git a/README.md b/README.md
index 467e66f..d32dd68 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,11 @@
# rand_core
-[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
-[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core)
[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core)
[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core)
-[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
Core traits and error types of the [rand] library, plus tools for implementing
RNGs.
@@ -44,7 +43,7 @@
The current version is:
```
-rand_core = "0.5.0"
+rand_core = "0.6.0"
```
Rand libs have inter-dependencies and make use of the
diff --git a/src/block.rs b/src/block.rs
index 0ab7458..005d071 100644
--- a/src/block.rs
+++ b/src/block.rs
@@ -21,12 +21,14 @@
//!
//! # Example
//!
-//! ```norun
+//! ```no_run
+//! use rand_core::{RngCore, SeedableRng};
//! use rand_core::block::{BlockRngCore, BlockRng};
//!
//! struct MyRngCore;
//!
//! impl BlockRngCore for MyRngCore {
+//! type Item = u32;
//! type Results = [u32; 16];
//!
//! fn generate(&mut self, results: &mut Self::Results) {
@@ -35,7 +37,7 @@
//! }
//!
//! impl SeedableRng for MyRngCore {
-//! type Seed = unimplemented!();
+//! type Seed = [u8; 32];
//! fn from_seed(seed: Self::Seed) -> Self {
//! unimplemented!()
//! }
@@ -44,17 +46,19 @@
//! // optionally, also implement CryptoRng for MyRngCore
//!
//! // Final RNG.
-//! type MyRng = BlockRng<u32, MyRngCore>;
+//! let mut rng = BlockRng::<MyRngCore>::seed_from_u64(0);
+//! println!("First value: {}", rng.next_u32());
//! ```
//!
//! [`BlockRngCore`]: crate::block::BlockRngCore
//! [`fill_bytes`]: RngCore::fill_bytes
-use core::convert::AsRef;
-use core::{fmt, ptr};
-#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
-use crate::{RngCore, CryptoRng, SeedableRng, Error};
use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks};
+use crate::{CryptoRng, Error, RngCore, SeedableRng};
+use core::convert::AsRef;
+use core::fmt;
+#[cfg(feature = "serde1")]
+use serde::{Deserialize, Serialize};
/// A trait for RNGs which do not generate random numbers individually, but in
/// blocks (typically `[u32; N]`). This technique is commonly used by
@@ -73,7 +77,6 @@
fn generate(&mut self, results: &mut Self::Results);
}
-
/// A wrapper type implementing [`RngCore`] for some type implementing
/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement
/// a full RNG from just a `generate` function.
@@ -110,7 +113,7 @@
/// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Clone)]
-#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct BlockRng<R: BlockRngCore + ?Sized> {
results: R::Results,
index: usize,
@@ -122,10 +125,10 @@
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()
+ .field("core", &self.core)
+ .field("result_len", &self.results.as_ref().len())
+ .field("index", &self.index)
+ .finish()
}
}
@@ -133,7 +136,7 @@
/// Create a new `BlockRng` from an existing RNG implementing
/// `BlockRngCore`. Results will be generated on first use.
#[inline]
- pub fn new(core: R) -> BlockRng<R>{
+ pub fn new(core: R) -> BlockRng<R> {
let results_empty = R::Results::default();
BlockRng {
core,
@@ -169,8 +172,9 @@
}
}
-impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R>
-where <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
+impl<R: BlockRngCore<Item = u32>> RngCore for BlockRng<R>
+where
+ <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>,
{
#[inline]
fn next_u32(&mut self) -> u32 {
@@ -186,22 +190,14 @@
#[inline]
fn next_u64(&mut self) -> u64 {
let read_u64 = |results: &[u32], index| {
- if cfg!(any(target_endian = "little")) {
- // requires little-endian CPU
- #[allow(clippy::cast_ptr_alignment)] // false positive
- let ptr: *const u64 = results[index..=index+1].as_ptr() as *const u64;
- unsafe { ptr::read_unaligned(ptr) }
- } else {
- let x = u64::from(results[index]);
- let y = u64::from(results[index + 1]);
- (y << 32) | x
- }
+ let data = &results[index..=index + 1];
+ u64::from(data[1]) << 32 | u64::from(data[0])
};
let len = self.results.as_ref().len();
let index = self.index;
- if index < len-1 {
+ if index < len - 1 {
self.index += 2;
// Read an u64 from the current index
read_u64(self.results.as_ref(), index)
@@ -209,7 +205,7 @@
self.generate_and_set(2);
read_u64(self.results.as_ref(), 0)
} else {
- let x = u64::from(self.results.as_ref()[len-1]);
+ 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
@@ -224,8 +220,7 @@
self.generate_and_set(0);
}
let (consumed_u32, filled_u8) =
- fill_via_u32_chunks(&self.results.as_ref()[self.index..],
- &mut dest[read_len..]);
+ fill_via_u32_chunks(&self.results.as_ref()[self.index..], &mut dest[read_len..]);
self.index += consumed_u32;
read_len += filled_u8;
@@ -258,8 +253,6 @@
}
}
-
-
/// A wrapper type implementing [`RngCore`] for some type implementing
/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement
/// a full RNG from just a `generate` function.
@@ -283,7 +276,7 @@
/// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Clone)]
-#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct BlockRng64<R: BlockRngCore + ?Sized> {
results: R::Results,
index: usize,
@@ -296,11 +289,11 @@
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()
+ .field("core", &self.core)
+ .field("result_len", &self.results.as_ref().len())
+ .field("index", &self.index)
+ .field("half_used", &self.half_used)
+ .finish()
}
}
@@ -308,7 +301,7 @@
/// Create a new `BlockRng` from an existing RNG implementing
/// `BlockRngCore`. Results will be generated on first use.
#[inline]
- pub fn new(core: R) -> BlockRng64<R>{
+ pub fn new(core: R) -> BlockRng64<R> {
let results_empty = R::Results::default();
BlockRng64 {
core,
@@ -347,8 +340,9 @@
}
}
-impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R>
-where <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]>
+impl<R: BlockRngCore<Item = u64>> RngCore for BlockRng64<R>
+where
+ <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]>,
{
#[inline]
fn next_u32(&mut self) -> u32 {
@@ -366,8 +360,7 @@
// Index as if this is a u32 slice.
unsafe {
- let results =
- &*(self.results.as_ref() as *const [u64] as *const [u32]);
+ let results = &*(self.results.as_ref() as *const [u64] as *const [u32]);
if cfg!(target_endian = "little") {
*results.get_unchecked(index)
} else {
@@ -399,9 +392,10 @@
self.index = 0;
}
- let (consumed_u64, filled_u8) =
- fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..],
- &mut dest[read_len..]);
+ 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;
diff --git a/src/error.rs b/src/error.rs
index 30b095c..a64c430 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -11,6 +11,7 @@
use core::fmt;
use core::num::NonZeroU32;
+#[cfg(feature = "std")] use std::boxed::Box;
/// Error type of random number generators
///
@@ -18,54 +19,64 @@
/// possible implementations: with `std` a boxed `Error` trait object is stored,
/// while with `no_std` we merely store an error code.
pub struct Error {
- #[cfg(feature="std")]
+ #[cfg(feature = "std")]
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
- #[cfg(not(feature="std"))]
+ #[cfg(not(feature = "std"))]
code: NonZeroU32,
}
impl Error {
+ /// Codes at or above this point can be used by users to define their own
+ /// custom errors.
+ ///
+ /// This has a fixed value of `(1 << 31) + (1 << 30) = 0xC000_0000`,
+ /// therefore the number of values available for custom codes is `1 << 30`.
+ ///
+ /// This is identical to [`getrandom::Error::CUSTOM_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.CUSTOM_START).
+ pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
+ /// Codes below this point represent OS Errors (i.e. positive i32 values).
+ /// Codes at or above this point, but below [`Error::CUSTOM_START`] are
+ /// reserved for use by the `rand` and `getrandom` crates.
+ ///
+ /// This is identical to [`getrandom::Error::INTERNAL_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.INTERNAL_START).
+ pub const INTERNAL_START: u32 = 1 << 31;
+
/// Construct from any type supporting `std::error::Error`
- ///
+ ///
/// Available only when configured with `std`.
- ///
+ ///
/// See also `From<NonZeroU32>`, which is available with and without `std`.
- #[cfg(feature="std")]
+ #[cfg(feature = "std")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn new<E>(err: E) -> Self
- where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>
+ where
+ E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
Error { inner: err.into() }
}
-
+
/// Reference the inner error (`std` only)
- ///
+ ///
/// When configured with `std`, this is a trivial operation and never
/// panics. Without `std`, this method is simply unavailable.
- #[cfg(feature="std")]
+ #[cfg(feature = "std")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
&*self.inner
}
-
+
/// Unwrap the inner error (`std` only)
- ///
+ ///
/// When configured with `std`, this is a trivial operation and never
/// panics. Without `std`, this method is simply unavailable.
- #[cfg(feature="std")]
+ #[cfg(feature = "std")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[inline]
pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
self.inner
}
-
- /// Codes below this point represent OS Errors (i.e. positive i32 values).
- /// Codes at or above this point, but below [`Error::CUSTOM_START`] are
- /// reserved for use by the `rand` and `getrandom` crates.
- pub const INTERNAL_START: u32 = 1 << 31;
-
- /// Codes at or above this point can be used by users to define their own
- /// custom errors.
- pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
/// Extract the raw OS error code (if this error came from the OS)
///
@@ -74,29 +85,31 @@
/// error value can still be formatted via the `Diplay` implementation.
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
- #[cfg(feature="std")] {
+ #[cfg(feature = "std")]
+ {
if let Some(e) = self.inner.downcast_ref::<std::io::Error>() {
return e.raw_os_error();
}
}
match self.code() {
- Some(code) if u32::from(code) < Self::INTERNAL_START =>
- Some(u32::from(code) as i32),
+ Some(code) if u32::from(code) < Self::INTERNAL_START => Some(u32::from(code) as i32),
_ => None,
}
}
/// Retrieve the error code, if any.
- ///
+ ///
/// If this `Error` was constructed via `From<NonZeroU32>`, then this method
/// will return this `NonZeroU32` code (for `no_std` this is always the
/// case). Otherwise, this method will return `None`.
#[inline]
pub fn code(&self) -> Option<NonZeroU32> {
- #[cfg(feature="std")] {
+ #[cfg(feature = "std")]
+ {
self.inner.downcast_ref::<ErrorCode>().map(|c| c.0)
}
- #[cfg(not(feature="std"))] {
+ #[cfg(not(feature = "std"))]
+ {
Some(self.code)
}
}
@@ -104,13 +117,16 @@
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- #[cfg(feature="std")] {
+ #[cfg(feature = "std")]
+ {
write!(f, "Error {{ inner: {:?} }}", self.inner)
}
- #[cfg(all(feature="getrandom", not(feature="std")))] {
+ #[cfg(all(feature = "getrandom", not(feature = "std")))]
+ {
getrandom::Error::from(self.code).fmt(f)
}
- #[cfg(not(feature="getrandom"))] {
+ #[cfg(not(feature = "getrandom"))]
+ {
write!(f, "Error {{ code: {} }}", self.code)
}
}
@@ -118,13 +134,16 @@
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- #[cfg(feature="std")] {
+ #[cfg(feature = "std")]
+ {
write!(f, "{}", self.inner)
}
- #[cfg(all(feature="getrandom", not(feature="std")))] {
+ #[cfg(all(feature = "getrandom", not(feature = "std")))]
+ {
getrandom::Error::from(self.code).fmt(f)
}
- #[cfg(not(feature="getrandom"))] {
+ #[cfg(not(feature = "getrandom"))]
+ {
write!(f, "error code {}", self.code)
}
}
@@ -133,29 +152,37 @@
impl From<NonZeroU32> for Error {
#[inline]
fn from(code: NonZeroU32) -> Self {
- #[cfg(feature="std")] {
- Error { inner: Box::new(ErrorCode(code)) }
+ #[cfg(feature = "std")]
+ {
+ Error {
+ inner: Box::new(ErrorCode(code)),
+ }
}
- #[cfg(not(feature="std"))] {
+ #[cfg(not(feature = "std"))]
+ {
Error { code }
}
}
}
-#[cfg(feature="getrandom")]
+#[cfg(feature = "getrandom")]
impl From<getrandom::Error> for Error {
#[inline]
fn from(error: getrandom::Error) -> Self {
- #[cfg(feature="std")] {
- Error { inner: Box::new(error) }
+ #[cfg(feature = "std")]
+ {
+ Error {
+ inner: Box::new(error),
+ }
}
- #[cfg(not(feature="std"))] {
+ #[cfg(not(feature = "std"))]
+ {
Error { code: error.code() }
}
}
}
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
impl std::error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
@@ -163,7 +190,7 @@
}
}
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
impl From<Error> for std::io::Error {
#[inline]
fn from(error: Error) -> Self {
@@ -175,16 +202,27 @@
}
}
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
#[derive(Debug, Copy, Clone)]
struct ErrorCode(NonZeroU32);
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "error code {}", self.0)
}
}
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
impl std::error::Error for ErrorCode {}
+
+#[cfg(test)]
+mod test {
+ #[cfg(feature = "getrandom")]
+ #[test]
+ fn test_error_codes() {
+ // Make sure the values are the same as in `getrandom`.
+ assert_eq!(super::Error::CUSTOM_START, getrandom::Error::CUSTOM_START);
+ assert_eq!(super::Error::INTERNAL_START, getrandom::Error::INTERNAL_START);
+ }
+}
diff --git a/src/impls.rs b/src/impls.rs
index dee4ed1..2588a72 100644
--- a/src/impls.rs
+++ b/src/impls.rs
@@ -17,12 +17,8 @@
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
-use core::ptr::copy_nonoverlapping;
-use core::slice;
-use core::cmp::min;
-use core::mem::size_of;
use crate::RngCore;
-
+use core::cmp::min;
/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
@@ -41,7 +37,7 @@
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
let mut left = dest;
while left.len() >= 8 {
- let (l, r) = {left}.split_at_mut(8);
+ let (l, r) = { left }.split_at_mut(8);
left = r;
let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
l.copy_from_slice(&chunk);
@@ -56,45 +52,36 @@
}
}
-macro_rules! impl_uint_from_fill {
- ($rng:expr, $ty:ty, $N:expr) => ({
- debug_assert!($N == size_of::<$ty>());
-
- let mut int: $ty = 0;
- unsafe {
- let ptr = &mut int as *mut $ty as *mut u8;
- let slice = slice::from_raw_parts_mut(ptr, $N);
- $rng.fill_bytes(slice);
- }
- int
- });
-}
-
macro_rules! fill_via_chunks {
- ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
- let chunk_size_u8 = min($src.len() * $size, $dst.len());
- let chunk_size = (chunk_size_u8 + $size - 1) / $size;
- if cfg!(target_endian="little") {
+ ($src:expr, $dst:expr, $ty:ty) => {{
+ const SIZE: usize = core::mem::size_of::<$ty>();
+ let chunk_size_u8 = min($src.len() * SIZE, $dst.len());
+ let chunk_size = (chunk_size_u8 + SIZE - 1) / SIZE;
+
+ // The following can be replaced with safe code, but unfortunately it's
+ // ca. 8% slower.
+ if cfg!(target_endian = "little") {
unsafe {
- copy_nonoverlapping(
+ core::ptr::copy_nonoverlapping(
$src.as_ptr() as *const u8,
$dst.as_mut_ptr(),
chunk_size_u8);
}
} else {
- for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
+ for (&n, chunk) in $src.iter().zip($dst.chunks_mut(SIZE)) {
let tmp = n.to_le();
let src_ptr = &tmp as *const $ty as *const u8;
unsafe {
- copy_nonoverlapping(src_ptr,
- chunk.as_mut_ptr(),
- chunk.len());
+ core::ptr::copy_nonoverlapping(
+ src_ptr,
+ chunk.as_mut_ptr(),
+ chunk.len());
}
}
}
(chunk_size, chunk_size_u8)
- });
+ }};
}
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
@@ -128,7 +115,7 @@
/// }
/// ```
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
- fill_via_chunks!(src, dest, u32, 4)
+ fill_via_chunks!(src, dest, u32)
}
/// Implement `fill_bytes` by reading chunks from the output buffer of a block
@@ -142,17 +129,56 @@
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
- fill_via_chunks!(src, dest, u64, 8)
+ fill_via_chunks!(src, dest, u64)
}
/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
- impl_uint_from_fill!(rng, u32, 4)
+ let mut buf = [0; 4];
+ rng.fill_bytes(&mut buf);
+ u32::from_le_bytes(buf)
}
/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
- impl_uint_from_fill!(rng, u64, 8)
+ let mut buf = [0; 8];
+ rng.fill_bytes(&mut buf);
+ u64::from_le_bytes(buf)
}
-// TODO: implement tests for the above
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_fill_via_u32_chunks() {
+ let src = [1, 2, 3];
+ let mut dst = [0u8; 11];
+ assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 11));
+ assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);
+
+ let mut dst = [0u8; 13];
+ assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 12));
+ assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);
+
+ let mut dst = [0u8; 5];
+ assert_eq!(fill_via_u32_chunks(&src, &mut dst), (2, 5));
+ assert_eq!(dst, [1, 0, 0, 0, 2]);
+ }
+
+ #[test]
+ fn test_fill_via_u64_chunks() {
+ let src = [1, 2];
+ let mut dst = [0u8; 11];
+ assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 11));
+ assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);
+
+ let mut dst = [0u8; 17];
+ assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 16));
+ assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+ let mut dst = [0u8; 5];
+ assert_eq!(fill_via_u64_chunks(&src, &mut dst), (1, 5));
+ assert_eq!(dst, [1, 0, 0, 0, 0]);
+ }
+}
diff --git a/src/le.rs b/src/le.rs
index 266651f..fa33892 100644
--- a/src/le.rs
+++ b/src/le.rs
@@ -7,61 +7,49 @@
// except according to those terms.
//! Little-Endian utilities
-//!
+//!
//! Little-Endian order has been chosen for internal usage; this makes some
//! useful functions available.
-use core::ptr;
-
-macro_rules! read_slice {
- ($src:expr, $dst:expr, $size:expr, $which:ident) => {{
- assert_eq!($src.len(), $size * $dst.len());
-
- unsafe {
- ptr::copy_nonoverlapping(
- $src.as_ptr(),
- $dst.as_mut_ptr() as *mut u8,
- $src.len());
- }
- for v in $dst.iter_mut() {
- *v = v.$which();
- }
- }};
-}
+use core::convert::TryInto;
/// Reads unsigned 32 bit integers from `src` into `dst`.
-/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
- read_slice!(src, dst, 4, to_le);
+ assert!(4 * src.len() >= dst.len());
+ for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) {
+ *out = u32::from_le_bytes(chunk.try_into().unwrap());
+ }
}
/// Reads unsigned 64 bit integers from `src` into `dst`.
-/// Borrowed from the `byteorder` crate.
#[inline]
pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
- read_slice!(src, dst, 8, to_le);
+ assert!(8 * src.len() >= dst.len());
+ for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) {
+ *out = u64::from_le_bytes(chunk.try_into().unwrap());
+ }
}
#[test]
fn test_read() {
let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
-
+
let mut buf = [0u32; 4];
read_u32_into(&bytes, &mut buf);
assert_eq!(buf[0], 0x04030201);
assert_eq!(buf[3], 0x100F0E0D);
-
+
let mut buf = [0u32; 3];
- read_u32_into(&bytes[1..13], &mut buf); // unaligned
+ read_u32_into(&bytes[1..13], &mut buf); // unaligned
assert_eq!(buf[0], 0x05040302);
assert_eq!(buf[2], 0x0D0C0B0A);
-
+
let mut buf = [0u64; 2];
read_u64_into(&bytes, &mut buf);
assert_eq!(buf[0], 0x0807060504030201);
assert_eq!(buf[1], 0x100F0E0D0C0B0A09);
-
+
let mut buf = [0u64; 1];
read_u64_into(&bytes[7..15], &mut buf); // unaligned
assert_eq!(buf[0], 0x0F0E0D0C0B0A0908);
diff --git a/src/lib.rs b/src/lib.rs
index d8e0189..ff553a3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,35 +27,33 @@
//!
//! [`rand`]: https://docs.rs/rand
-#![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://rust-random.github.io/rand/")]
-
+#![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://rust-random.github.io/rand/"
+)]
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
+#![no_std]
-#![allow(clippy::unreadable_literal)]
-
-#![cfg_attr(not(feature="std"), no_std)]
-
-
-use core::default::Default;
use core::convert::AsMut;
-use core::ptr::copy_nonoverlapping;
+use core::default::Default;
-#[cfg(all(feature="alloc", not(feature="std")))] extern crate alloc;
-#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
+#[cfg(feature = "std")] extern crate std;
+#[cfg(feature = "alloc")] extern crate alloc;
+#[cfg(feature = "alloc")] use alloc::boxed::Box;
pub use error::Error;
-#[cfg(feature="getrandom")] pub use os::OsRng;
+#[cfg(feature = "getrandom")] pub use os::OsRng;
-mod error;
pub mod block;
+mod error;
pub mod impls;
pub mod le;
-#[cfg(feature="getrandom")] mod os;
+#[cfg(feature = "getrandom")] mod os;
/// The core of a random number generator.
@@ -69,7 +67,9 @@
/// optimal implementation of each is dependent on the type of generator. There
/// is no required relationship between the output of each; e.g. many
/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64`
-/// values and drop any remaining unused bytes.
+/// values and drop any remaining unused bytes. The same can happen with the
+/// [`next_u32`] and [`next_u64`] methods, implementations may discard some
+/// random bits for efficiency.
///
/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error
/// handling; it is not deemed sufficiently useful to add equivalents for
@@ -139,24 +139,22 @@
///
/// RNGs must implement at least one method from this trait directly. In
/// the case this method is not implemented directly, it can be implemented
- /// using `self.next_u64() as u32` or via
- /// [`fill_bytes`](impls::next_u32_via_fill).
+ /// using `self.next_u64() as u32` or via [`impls::next_u32_via_fill`].
fn next_u32(&mut self) -> u32;
/// Return the next random `u64`.
///
/// 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`](impls::next_u64_via_u32) or via
- /// [`fill_bytes`](impls::next_u64_via_fill).
+ /// via [`impls::next_u64_via_u32`] or via [`impls::next_u64_via_fill`].
fn next_u64(&mut self) -> u64;
/// Fill `dest` with random data.
///
/// 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_u*`](impls::fill_bytes_via_next) or
- /// via [`try_fill_bytes`](RngCore::try_fill_bytes); if this generator can
+ /// via [`impls::fill_bytes_via_next`] or
+ /// via [`RngCore::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).
@@ -174,12 +172,10 @@
/// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used
/// directly to generate keys and to seed (infallible) PRNGs.
///
- /// Other than error handling, this method is identical to [`fill_bytes`];
+ /// Other than error handling, this method is identical to [`RngCore::fill_bytes`];
/// thus this may be implemented using `Ok(self.fill_bytes(dest))` or
/// `fill_bytes` may be implemented with
/// `self.try_fill_bytes(dest).unwrap()` or more specific error handling.
- ///
- /// [`fill_bytes`]: RngCore::fill_bytes
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>;
}
@@ -316,12 +312,8 @@
// Use PCG output function with to_le to generate x:
let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
let rot = (state >> 59) as u32;
- let x = xorshifted.rotate_right(rot).to_le();
-
- unsafe {
- let p = &x as *const u32 as *const u8;
- copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len());
- }
+ let x = xorshifted.rotate_right(rot);
+ chunk.copy_from_slice(&x.to_le_bytes());
}
Self::from_seed(seed)
@@ -351,7 +343,6 @@
/// (in prior versions this was not required).
///
/// [`rand`]: https://docs.rs/rand
- /// [`rand_os`]: https://docs.rs/rand_os
fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
let mut seed = Self::Seed::default();
rng.try_fill_bytes(seed.as_mut())?;
@@ -372,7 +363,8 @@
/// If [`getrandom`] is unable to provide secure entropy this method will panic.
///
/// [`getrandom`]: https://docs.rs/getrandom
- #[cfg(feature="getrandom")]
+ #[cfg(feature = "getrandom")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
fn from_entropy() -> Self {
let mut seed = Self::Seed::default();
if let Err(err) = getrandom::getrandom(seed.as_mut()) {
@@ -410,7 +402,7 @@
// Implement `RngCore` for boxed references to an `RngCore`.
// Force inlining all functions, so that it is up to the `RngCore`
// implementation and the optimizer to decide on inlining.
-#[cfg(feature="alloc")]
+#[cfg(feature = "alloc")]
impl<R: RngCore + ?Sized> RngCore for Box<R> {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
@@ -433,7 +425,7 @@
}
}
-#[cfg(feature="std")]
+#[cfg(feature = "std")]
impl std::io::Read for dyn RngCore {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
self.try_fill_bytes(buf)?;
@@ -445,7 +437,7 @@
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
// Implement `CryptoRng` for boxed references to an `CryptoRng`.
-#[cfg(feature="alloc")]
+#[cfg(feature = "alloc")]
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
#[cfg(test)]
@@ -457,6 +449,7 @@
struct SeedableNum(u64);
impl SeedableRng for SeedableNum {
type Seed = [u8; 8];
+
fn from_seed(seed: Self::Seed) -> Self {
let mut x = [0u64; 1];
le::read_u64_into(&seed, &mut x);
@@ -480,7 +473,9 @@
assert!(weight >= 20 && weight <= 44);
for (i2, r2) in results.iter().enumerate() {
- if i1 == i2 { continue; }
+ if i1 == i2 {
+ continue;
+ }
let diff_weight = (r1 ^ r2).count_ones();
assert!(diff_weight >= 20);
}
diff --git a/src/os.rs b/src/os.rs
index fc23a57..6cd1b9c 100644
--- a/src/os.rs
+++ b/src/os.rs
@@ -7,12 +7,11 @@
// except according to those terms.
//! Interface to the random number generator of the operating system.
-// Note: keep this code in sync with the rand_os crate!
+use crate::{impls, CryptoRng, Error, RngCore};
use getrandom::getrandom;
-use crate::{CryptoRng, RngCore, Error, impls};
-/// A random number generator that retrieves randomness from from the
+/// A random number generator that retrieves randomness from the
/// operating system.
///
/// This is a zero-sized struct. It can be freely constructed with `OsRng`.
@@ -44,6 +43,7 @@
/// ```
///
/// [getrandom]: https://crates.io/crates/getrandom
+#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[derive(Clone, Copy, Debug, Default)]
pub struct OsRng;