From 4275e2563814faa13ccc87753c567d03997c6873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 24 Nov 2025 14:53:23 +0300 Subject: [PATCH 1/3] Add `UnwrappingSysRng` --- src/lib.rs | 2 +- src/sys_rng.rs | 72 ++++++++++++++++++++++++++++++++++++++---------- tests/sys_rng.rs | 54 +++++++++++++++++++++++++++++++----- 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed69ad23..a955f3b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ mod sys_rng; #[cfg(feature = "sys_rng")] pub use rand_core; #[cfg(feature = "sys_rng")] -pub use sys_rng::SysRng; +pub use sys_rng::{SysRng, UnwrappingSysRng}; pub use crate::error::{Error, RawOsError}; diff --git a/src/sys_rng.rs b/src/sys_rng.rs index d7c019e1..5fc8a412 100644 --- a/src/sys_rng.rs +++ b/src/sys_rng.rs @@ -1,11 +1,14 @@ 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 /// @@ -13,22 +16,17 @@ use rand_core::{TryCryptoRng, 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; + +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 {} diff --git a/tests/sys_rng.rs b/tests/sys_rng.rs index 541912d2..266232d9 100644 --- a/tests/sys_rng.rs +++ b/tests/sys_rng.rs @@ -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.try_fill_bytes(&mut x); + let mut y = [0u8; N]; + UnwrappingSysRng.try_fill_bytes(&mut y); + + assert_ne!(x, [0; N]); + assert_ne!(y, [0; N]); + assert!(x != y); } From 47328910d57feae602b725b75b2d6a91c31588c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 24 Nov 2025 14:55:12 +0300 Subject: [PATCH 2/3] fix `test_unwrapping_sys_rng` --- tests/sys_rng.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/sys_rng.rs b/tests/sys_rng.rs index 266232d9..53773282 100644 --- a/tests/sys_rng.rs +++ b/tests/sys_rng.rs @@ -47,9 +47,9 @@ fn test_unwrapping_sys_rng() { assert!(x != y); let mut x = [0u8; N]; - UnwrappingSysRng.try_fill_bytes(&mut x); + UnwrappingSysRng.fill_bytes(&mut x); let mut y = [0u8; N]; - UnwrappingSysRng.try_fill_bytes(&mut y); + UnwrappingSysRng.fill_bytes(&mut y); assert_ne!(x, [0; N]); assert_ne!(y, [0; N]); From c52e99cc4ba36a4c1cc2cdee652594880e2853bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 24 Nov 2025 14:59:09 +0300 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28162ef4..ee8193cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `RawOsError` type alias [#739] - `SysRng` behind new feature `sys_rng` [#751] +- `UnwrappingSysRng` behind new feature `sys_rng` [#754] ### Changed - Use Edition 2024 and MSRV 1.85 [#749] @@ -16,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#739]: https://github.com/rust-random/getrandom/pull/739 [#749]: https://github.com/rust-random/getrandom/pull/749 [#751]: https://github.com/rust-random/getrandom/pull/751 +[#754]: https://github.com/rust-random/getrandom/pull/754 ## [0.3.4] - 2025-10-14