-
Notifications
You must be signed in to change notification settings - Fork 240
Add UnwrappingSysRng
#754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add UnwrappingSysRng
#754
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,32 @@ | ||
| use crate::Error; | ||
| use rand_core::{TryCryptoRng, TryRngCore}; | ||
| use rand_core::{CryptoRng, RngCore, TryCryptoRng, TryRngCore}; | ||
|
|
||
| /// A [`TryRngCore`] interface over the system's preferred random number source | ||
| /// A [`TryRngCore`] interface over the system's preferred random number source. | ||
| /// | ||
| /// This is a zero-sized struct. It can be freely constructed with just `SysRng`. | ||
| /// | ||
| /// This struct is also available as [`rand::rngs::SysRng`] when using [rand]. | ||
| /// This struct is also available as [`rand::rngs::SysRng`] when using [`rand`]. | ||
| /// | ||
| /// If you don't care about potential (but extremely unlikely in practice) errors, | ||
| /// you can use [`UnwrappingSysRng`] instead. | ||
| /// | ||
| /// # Usage example | ||
| /// | ||
| /// `SysRng` implements [`TryRngCore`]: | ||
| /// ``` | ||
| /// use getrandom::{rand_core::TryRngCore, SysRng}; | ||
| /// | ||
| /// # fn main() -> Result<(), getrandom::Error> { | ||
| /// let mut key = [0u8; 32]; | ||
| /// SysRng.try_fill_bytes(&mut key).unwrap(); | ||
| /// ``` | ||
| /// | ||
| /// Using it as an [`RngCore`] is possible using [`TryRngCore::unwrap_err`]: | ||
| /// ``` | ||
| /// use getrandom::rand_core::{TryRngCore, RngCore}; | ||
| /// use getrandom::SysRng; | ||
| /// SysRng.try_fill_bytes(&mut key)?; | ||
| /// | ||
| /// let mut rng = SysRng.unwrap_err(); | ||
| /// let random_u64 = rng.next_u64(); | ||
| /// let x: u32 = SysRng.try_next_u32()?; | ||
| /// let y: u64 = SysRng.try_next_u64()?; | ||
| /// # Ok(()) } | ||
| /// ``` | ||
| /// | ||
| /// [rand]: https://crates.io/crates/rand | ||
| /// [`rand`]: https://crates.io/crates/rand | ||
| /// [`rand::rngs::SysRng`]: https://docs.rs/rand/latest/rand/rngs/struct.SysRng.html | ||
| /// [`RngCore`]: rand_core::RngCore | ||
| #[derive(Clone, Copy, Debug, Default)] | ||
| pub struct SysRng; | ||
|
|
||
|
|
@@ -52,3 +50,49 @@ impl TryRngCore for SysRng { | |
| } | ||
|
|
||
| impl TryCryptoRng for SysRng {} | ||
|
|
||
| /// A potentially-panicking [`RngCore`] interface over the system's preferred random number source. | ||
| /// | ||
| /// This is a zero-sized struct. It can be freely constructed with just `UnwrappingSysRng`. | ||
| /// | ||
| /// If possible, we recommend to use [`SysRng`] instead and to properly handle potential errors. | ||
| /// | ||
| /// This struct is also available as [`rand::rngs::UnwrappingSysRng`] when using [`rand`]. | ||
| /// | ||
| /// # Usage example | ||
| /// | ||
| /// `UnwrappingSysRng` implements [`RngCore`]: | ||
| /// ``` | ||
| /// use getrandom::{rand_core::RngCore, UnwrappingSysRng}; | ||
| /// | ||
| /// let mut key = [0u8; 32]; | ||
| /// UnwrappingSysRng.fill_bytes(&mut key); | ||
| /// | ||
| /// let x: u32 = UnwrappingSysRng.next_u32(); | ||
| /// let y: u64 = UnwrappingSysRng.next_u64(); | ||
| /// ``` | ||
| /// | ||
| /// [`rand`]: https://crates.io/crates/rand | ||
| /// [`rand::rngs::UnwrappingSysRng`]: https://docs.rs/rand/latest/rand/rngs/struct.UnwrappingSysRng.html | ||
| /// [`RngCore`]: rand_core::RngCore | ||
| #[derive(Clone, Copy, Debug, Default)] | ||
| pub struct UnwrappingSysRng; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally, I'm not a fan of introducing another type which is just " Currently, there are two ways to already do this with
I don't think we need to add a third way, especially if (as you say) we recommend using I think we should instead update the docstring for
## Use with [`RngCore`]
Unlike the use of [`TryRngCore`] above, the [`RngCore`] trait does not allow returning
an error type. While it is possible for [`SysRng`]/[`fill`] to fail, this is usually
uncommon on most platforms (see [link to main crate docs]). For this reason, users may
want to wrap [`SysRng`] with [`rand_core::UnwrapErr`], to automatically unwrap the unlikely
errors.
```rust
use getrandom::{SysRng, rand_core::{RngCore, UnwrapErr}};
let x: u32 = UnwrapErr(SysRng).next_u32();
let y: u64 = UnwrapErr(SysRng).next_u64();
```
This can also be done via the [`TryRngCore::unwrap_err()`] method as
`let mut rng = SysRng.unwrap_err();`
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't say we have "two ways" right now. They are doing the same thing, but expressed differently. Following your classification we would have a bunch of other "different" ways such as The main rationale for the additional type is that in practice the unwrapped variant probably will be used much more often than The I don't think
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By users of But even for But I may be wrong. Which in this case is fine since there is no reason this could not be added in the future.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It looks like
It's likely to result in an annoying mix of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some of those uses are ancient, as evidenced by usage of Also, basically all of these uses are just constructing an instance of I wonder if we should make |
||
|
|
||
| impl RngCore for UnwrappingSysRng { | ||
| #[inline] | ||
| fn next_u32(&mut self) -> u32 { | ||
| crate::u32().unwrap() | ||
| } | ||
|
|
||
| #[inline] | ||
| fn next_u64(&mut self) -> u64 { | ||
| crate::u64().unwrap() | ||
| } | ||
|
|
||
| #[inline] | ||
| fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
| crate::fill(dest).unwrap() | ||
| } | ||
| } | ||
|
|
||
| impl CryptoRng for UnwrappingSysRng {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,57 @@ | ||
| #![cfg(feature = "sys_rng")] | ||
|
|
||
| use getrandom::SysRng; | ||
| use getrandom::rand_core::TryRngCore; | ||
| use core::array::from_fn; | ||
| use getrandom::{ | ||
| SysRng, UnwrappingSysRng, | ||
| rand_core::{RngCore, TryRngCore}, | ||
| }; | ||
|
|
||
| const N: usize = 32; | ||
|
|
||
| #[test] | ||
| fn test_sys_rng() { | ||
| let x = SysRng.try_next_u64().unwrap(); | ||
| let y = SysRng.try_next_u64().unwrap(); | ||
| assert!(x != 0); | ||
| let x: [u64; N] = from_fn(|_| SysRng.try_next_u64().unwrap()); | ||
| let y: [u64; N] = from_fn(|_| SysRng.try_next_u64().unwrap()); | ||
| assert!(x.iter().all(|&val| val != 0)); | ||
| assert!(y.iter().all(|&val| val != 0)); | ||
| assert!(x != y); | ||
|
|
||
| let x: [u32; N] = from_fn(|_| SysRng.try_next_u32().unwrap()); | ||
| let y: [u32; N] = from_fn(|_| SysRng.try_next_u32().unwrap()); | ||
| assert!(x.iter().all(|&val| val != 0)); | ||
| assert!(y.iter().all(|&val| val != 0)); | ||
| assert!(x != y); | ||
|
|
||
| let mut x = [0u8; N]; | ||
| SysRng.try_fill_bytes(&mut x).unwrap(); | ||
| let mut y = [0u8; N]; | ||
| SysRng.try_fill_bytes(&mut y).unwrap(); | ||
|
|
||
| assert_ne!(x, [0; N]); | ||
| assert_ne!(y, [0; N]); | ||
| assert!(x != y); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_construction() { | ||
| assert!(SysRng.try_next_u64().unwrap() != 0); | ||
| fn test_unwrapping_sys_rng() { | ||
| let x: [u64; N] = from_fn(|_| UnwrappingSysRng.next_u64()); | ||
| let y: [u64; N] = from_fn(|_| UnwrappingSysRng.next_u64()); | ||
| assert!(x.iter().all(|&val| val != 0)); | ||
| assert!(y.iter().all(|&val| val != 0)); | ||
| assert!(x != y); | ||
|
|
||
| let x: [u32; N] = from_fn(|_| UnwrappingSysRng.next_u32()); | ||
| let y: [u32; N] = from_fn(|_| UnwrappingSysRng.next_u32()); | ||
| assert!(x.iter().all(|&val| val != 0)); | ||
| assert!(y.iter().all(|&val| val != 0)); | ||
| assert!(x != y); | ||
|
|
||
| let mut x = [0u8; N]; | ||
| UnwrappingSysRng.fill_bytes(&mut x); | ||
| let mut y = [0u8; N]; | ||
| UnwrappingSysRng.fill_bytes(&mut y); | ||
|
|
||
| assert_ne!(x, [0; N]); | ||
| assert_ne!(y, [0; N]); | ||
| assert!(x != y); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: rustdoc formats this as: