Skip to content

Commit 603bb37

Browse files
committed
Implement NewSeeded trait
1 parent de703be commit 603bb37

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed

src/jitter.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
//! Non-physical true random number generator based on timing jitter.
1818
19-
use {Rng, impls};
19+
use {Rng, Error, ErrorKind, impls};
2020

2121
use core::{fmt, mem, ptr};
2222
#[cfg(feature="std")]
@@ -115,6 +115,13 @@ impl ::std::error::Error for TimerError {
115115
}
116116
}
117117

118+
impl From<TimerError> for Error {
119+
fn from(err: TimerError) -> Error {
120+
Error::with_cause(ErrorKind::Unavailable,
121+
"timer jitter failed basic quality tests", err)
122+
}
123+
}
124+
118125
// Initialise to zero; must be positive
119126
#[cfg(feature="std")]
120127
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;

src/lib.rs

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,60 @@ pub trait SeedableRng: Sized {
793793
}
794794
}
795795

796+
797+
/// Seeding mechanism for PRNGs, providing a `new` function.
798+
/// This is the recommended way to create (pseudo) random number generators,
799+
/// unless a deterministic seed is desired (in which case
800+
/// `SeedableRng::from_seed` should be used).
801+
///
802+
/// Note: this trait is automatically implemented for any PRNG implementing
803+
/// `SeedableRng` and is not intended to be implemented by users.
804+
///
805+
/// ## Example
806+
///
807+
/// ```
808+
/// use rand::{StdRng, Rng, NewSeeded};
809+
///
810+
/// let mut rng = StdRng::new().unwrap();
811+
/// println!("Random die roll: {}", rng.gen_range(1, 7));
812+
/// ```
813+
#[cfg(feature="std")]
814+
pub trait NewSeeded: SeedableRng {
815+
/// Creates a new instance, automatically seeded with fresh entropy.
816+
///
817+
/// Normally this will use `OsRng`, but if that fails `JitterRng` will be
818+
/// used instead. Both should be suitable for cryptography. It is possible
819+
/// that both entropy sources will fail though unlikely.
820+
fn new() -> Result<Self, Error>;
821+
}
822+
823+
#[cfg(feature="std")]
824+
impl<R: SeedableRng> NewSeeded for R {
825+
fn new() -> Result<Self, Error> {
826+
// Note: error handling would be easier with try/catch blocks
827+
fn new_os<T: SeedableRng>() -> Result<T, Error> {
828+
let mut r = OsRng::new()?;
829+
T::from_rng(&mut r)
830+
}
831+
832+
fn new_jitter<T: SeedableRng>() -> Result<T, Error> {
833+
let mut r = JitterRng::new()?;
834+
T::from_rng(&mut r)
835+
}
836+
837+
new_os().or_else(|e1| {
838+
new_jitter().map_err(|_e2| {
839+
// TODO: log
840+
// TODO: can we somehow return both error sources?
841+
Error::with_cause(
842+
ErrorKind::Unavailable,
843+
"seeding a new RNG failed: both OS and Jitter entropy sources failed",
844+
e1)
845+
})
846+
})
847+
}
848+
}
849+
796850
/// A wrapper for generating floating point numbers uniformly in the
797851
/// open interval `(0,1)` (not including either endpoint).
798852
///
@@ -836,34 +890,6 @@ pub struct Closed01<F>(pub F);
836890
#[derive(Clone, Debug)]
837891
pub struct StdRng(IsaacWordRng);
838892

839-
impl StdRng {
840-
/// Create a randomly seeded instance of `StdRng`.
841-
///
842-
/// This is a very expensive operation as it has to read
843-
/// randomness from the operating system and use this in an
844-
/// expensive seeding operation. If one is only generating a small
845-
/// number of random numbers, or doesn't need the utmost speed for
846-
/// generating each number, `thread_rng` and/or `random` may be more
847-
/// appropriate.
848-
///
849-
/// Reading the randomness from the OS may fail, and any error is
850-
/// propagated via the `io::Result` return value.
851-
#[cfg(feature="std")]
852-
pub fn new() -> Result<StdRng, Error> {
853-
match OsRng::new() {
854-
Ok(mut r) => Ok(StdRng(r.gen())),
855-
Err(e1) => {
856-
match JitterRng::new() {
857-
Ok(mut r) => Ok(StdRng(r.gen())),
858-
Err(_) => {
859-
Err(e1)
860-
}
861-
}
862-
}
863-
}
864-
}
865-
}
866-
867893
impl Rng for StdRng {
868894
fn next_u32(&mut self) -> u32 {
869895
self.0.next_u32()
@@ -904,7 +930,7 @@ impl SeedableRng for StdRng {
904930
/// This will seed the generator with randomness from thread_rng.
905931
#[cfg(feature="std")]
906932
pub fn weak_rng() -> XorShiftRng {
907-
thread_rng().gen()
933+
XorShiftRng::new().unwrap()
908934
}
909935

910936
/// Controls how the thread-local RNG is reseeded.

0 commit comments

Comments
 (0)