Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ jobs:
- uses: Swatinem/rust-cache@v2
- run: cargo test
# Make sure enabling the std feature doesn't break anything
- run: cargo test --features=std
- run: |
cargo test --features=std
cargo test --features=rng
cargo test --features=std,rng
- if: ${{ matrix.toolchain == 'nightly' }}
run: cargo test --benches

Expand All @@ -53,27 +56,27 @@ jobs:
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- run: cargo test --target=${{ matrix.target }} --features=std
- run: cargo test --target=${{ matrix.target }} --features=std,rng
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo test --target=${{ matrix.target }} --features=std
run: cargo test --target=${{ matrix.target }} --features=std,rng
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="linux_raw"
run: cargo test --target=${{ matrix.target }} --features=std
run: cargo test --target=${{ matrix.target }} --features=std,rng
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_fallback
run: cargo test --features=std
run: cargo test --features=std,rng
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_test_linux_without_fallback
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_test_linux_without_fallback
run: cargo test --features=std
run: cargo test --features=std,rng
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
run: cargo test --features=std
run: cargo test --features=std,rng

ios:
name: iOS Simulator
Expand Down Expand Up @@ -123,7 +126,7 @@ jobs:
with:
toolchain: ${{ matrix.toolchain }}
- uses: Swatinem/rust-cache@v2
- run: cargo test --features=std
- run: cargo test --features=std,rng

windows7:
name: Windows 7 (on Windows 10)
Expand All @@ -136,8 +139,8 @@ jobs:
toolchain: nightly-2025-09-28
components: rust-src
- uses: Swatinem/rust-cache@v2
- run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std
- run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std
- run: cargo test --target=x86_64-win7-windows-msvc -Z build-std --features=std,rng
- run: cargo test --target=i686-win7-windows-msvc -Z build-std --features=std,rng

sanitizer-linux:
name: Sanitizer Linux
Expand Down Expand Up @@ -216,7 +219,7 @@ jobs:
wget -O - $URL | tar -xz -C ~/.cargo/bin
cross --version
- name: Test
run: cross test --no-fail-fast --target=${{ matrix.target }} --features=std
run: cross test --no-fail-fast --target=${{ matrix.target }} --features=std,rng

freebsd:
name: FreeBSD VM
Expand Down Expand Up @@ -273,14 +276,14 @@ jobs:
description: Web,
version: stable,
flags: '-Dwarnings --cfg getrandom_backend="wasm_js"',
args: '--features=std,wasm_js',
args: '--features=std,rng,wasm_js',
}
- {
description: Web with Atomics,
version: nightly,
components: rust-src,
flags: '-Dwarnings --cfg getrandom_backend="wasm_js" -Ctarget-feature=+atomics,+bulk-memory',
args: '--features=std,wasm_js -Zbuild-std=panic_abort,std',
args: '--features=std,rng,wasm_js -Zbuild-std=panic_abort,std',
}
steps:
- uses: actions/checkout@v5
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ repository = "https://github.com/rust-random/getrandom"
categories = ["os", "no-std"]
exclude = [".*"]

[package.metadata.docs.rs]
features = ["std", "rng"]

[features]
# Implement From<getrandom::Error> for std::io::Error and
# use std to retrieve OS error descriptions
Expand All @@ -23,8 +26,12 @@ std = []
# i.e. avoid unconditionally enabling it in library crates.
wasm_js = ["dep:wasm-bindgen", "dep:js-sys"]

# Provide OsRng over rand_core
rng = ["dep:rand_core"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about naming the feature os_rng (or sys_rng if the type will be renamed)?


[dependencies]
cfg-if = "1"
rand_core = { version = "0.10.0-rc-2", optional = true }

# getrandom / linux_android_with_fallback
[target.'cfg(all(any(target_os = "linux", target_os = "android"), not(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))))'.dependencies]
Expand Down Expand Up @@ -85,9 +92,6 @@ check-cfg = [
'cfg(target_os, values("cygwin"))', # TODO(MSRV 1.86): Remove this.
]

[package.metadata.docs.rs]
features = ["std"]

# workaround for https://github.com/cross-rs/cross/issues/1345
[package.metadata.cross.target.x86_64-unknown-netbsd]
pre-build = [
Expand Down
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ mod util;
#[cfg(feature = "std")]
mod error_std_impls;

#[cfg(feature = "rng")]
mod rng;
#[cfg(feature = "rng")]
pub use rand_core;
#[cfg(feature = "rng")]
pub use rng::OsRng;

pub use crate::error::{Error, RawOsError};

/// Fill `dest` with random bytes from the system's preferred random number source.
Expand Down
74 changes: 74 additions & 0 deletions src/rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! rand_core adapter
use crate::Error;
use rand_core::{TryCryptoRng, TryRngCore};

/// An RNG over the operating-system's random data source
///
/// This is a zero-sized struct. It can be freely constructed with just `OsRng`.
///
/// This struct is also available as [`rand::rngs::OsRng`] when using [rand].
///
/// # Usage example
///
/// `OsRng` implements [`TryRngCore`]:
/// ```
/// use getrandom::{rand_core::TryRngCore, OsRng};
///
/// let mut key = [0u8; 32];
/// OsRng.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::OsRng;
///
/// let mut rng = OsRng.unwrap_err();
/// let random_u64 = rng.next_u64();
/// ```
///
/// [rand]: https://crates.io/crates/rand
/// [`rand::rngs::OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html
/// [`RngCore`]: rand_core::RngCore
#[derive(Clone, Copy, Debug, Default)]
pub struct OsRng;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer for it to be named as SysRng, since OsRng can be a confusing name on no_std targets. To make migration easier we could add type OsRng = SysRng; alias in rand (with or without #[deprecated] attribute).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes some sense... some backends like RDRAND are not OS features.

@josephlr?


impl TryRngCore for OsRng {
type Error = Error;

#[inline]
fn try_next_u32(&mut self) -> Result<u32, Error> {
crate::u32()
}

#[inline]
fn try_next_u64(&mut self) -> Result<u64, Error> {
crate::u64()
}

#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
crate::fill(dest)
}
}

impl TryCryptoRng for OsRng {}

#[cfg(test)]
mod test {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to define these tests in tests/rng.rs or integrate them into the doctest.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Motivation? Having tests close to the feature definition is slightly preferable in my opinion (where tests are not too extensive at least).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My general preference is to keep public API tests in integration tests (i.e. in the tests folder) and/or doctest, while using test modules (i.e. unit tests) only for private API testing.

Since these tests are quite small, I think they can be simply merged into the OsRng doctest, potentially with # used to hide asserts.

Copy link
Member Author

@dhardy dhardy Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the motivation is to improve visibility of integration tests, then moving to tests makes sense.

I'm disinclined to push these into a doc-test since (a) it hides it, (b) I would normally assume that doc-tests are only for documentation purposes and (c) failure reporting for doc tests is worse (slower and worse messages) than for other types of test.

So I don't understand why you prefer both integration tests and doc tests over a local test module.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a matter of not duplicating tests which are already covered by doctests. I am fine with keeping the example as-is and moving the test module into the tests/ folder.

use super::*;

#[test]
fn test_os_rng() {
let x = OsRng.try_next_u64().unwrap();
let y = OsRng.try_next_u64().unwrap();
assert!(x != 0);
assert!(x != y);
}

#[test]
fn test_construction() {
assert!(OsRng.try_next_u64().unwrap() != 0);
}
}
Loading