Skip to content

Conversation

@dhardy
Copy link
Member

@dhardy dhardy commented Nov 10, 2025

This was mentioned elsewhere: rust-random/rand#1675

Adds rand_core as a dependency, which is one small crate.

This attempts to enable testing of rng in all CI tests.

@dhardy
Copy link
Member Author

dhardy commented Nov 18, 2025

@newpavlov your opinion on this please?

There is an alternative: the rand_os crate. I slightly prefer fewer crates but either is acceptable.

@newpavlov
Copy link
Member

As I wrote previously, personally, I have a slight preference for a separate crate. But I would be fine with this PR as well, if others prefer it.

P.S.: Note that rand_os recently got an "unmaintained" advisory: rustsec/advisory-db#2462

Copy link
Member

@josephlr josephlr left a comment

Choose a reason for hiding this comment

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

As I wrote previously, personally, I have a slight preference for a separate crate. But I would be fine with this PR as well, if others prefer it.

I think I would slightly lean towards having this as part of getrandom. A non-default additive feature seems like a good fit. I think the only complexity is figuring out what (if anything) this crate should re-export from rand_core.

- run: cargo test
# Make sure enabling the std feature doesn't break anything
- run: cargo test --features=std
- run: cargo test --features=std,rng
Copy link
Member

Choose a reason for hiding this comment

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

Should we have a test somewhere that rng works without the std feature? Maybe here we could have:

Suggested change
- run: cargo test --features=std,rng
- run: cargo test --features=std
- run: cargo test --features=rng
- run: cargo test --features=std,rng

I agree that having most of the testing use --features=std,rng is correct.

Cargo.toml Outdated
]

[package.metadata.docs.rs]
features = ["std"]
Copy link
Member

@josephlr josephlr Nov 19, 2025

Choose a reason for hiding this comment

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

This should be updated to include "rng" so that users can see the generated docs for stuff gated behind rng

Comment on lines 6 to 32
/// 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
/// ```
/// use getrandom::{rand_core::{TryRngCore, RngCore}, OsRng};
///
/// let mut key = [0u8; 32];
/// OsRng.try_fill_bytes(&mut key).unwrap();
///
/// 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
Copy link
Member

@josephlr josephlr Nov 19, 2025

Choose a reason for hiding this comment

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

Similar to the docs for getrandom::Error, we should mention that this will require a crate to enable the rng feature. We should also mention here if the rng feature will have different MSRV or stability guarantees going forward. Are we allowed to increase the minor version of rand_core (from say 0.10 to 0.11) when moving from getrandom 0.4.0 to getrandom 0.4.1?

Not sure what our policy should be, but we should document it.

Copy link
Member Author

Choose a reason for hiding this comment

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

doc-auto-cfg was stabilised so docs will note that OsRng requires feature rng, if that's what you mean.

Are we allowed to increase the minor version of rand_core (from say 0.10 to 0.11) when moving from getrandom 0.4.0 to getrandom 0.4.1?

That would break semver since rand_core_0_10::TryRngCore and rand_core_0_11::TryRngCore are considered separate traits, so it should be clear that we cannot do that.

We should also mention here if the rng feature will have different MSRV or stability guarantees going forward.

I don't see why it would.

Copy link
Member

Choose a reason for hiding this comment

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

doc-auto-cfg was stabilised

Are you sure? I thought it was just merged into doc_cfg. In RustCrypto we still use #![cfg_attr(docsrs, feature(doc_cfg))].

src/rng.rs Outdated
Comment on lines 49 to 60
#[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);
}
Copy link
Member

Choose a reason for hiding this comment

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

These should be in a mod test with #[cfg(test)]

src/lib.rs Outdated
#[cfg(feature = "rng")]
mod rng;
#[cfg(feature = "rng")]
pub extern crate 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.

Suggested change
pub extern crate rand_core;
pub use rand_core;

This is necessary for rustdoc to correctly:

  • Render descriptions for all the other items
  • Mark this re-export as gated behind the rng feature.

Copy link
Member Author

Choose a reason for hiding this comment

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

  • Mark this re-export as gated behind the rng feature.

It's not, but it does appear to cause render issues (all following text is fixed width / code). Weird.

src/rng.rs Outdated
Comment on lines 12 to 14
/// # Usage example
/// ```
/// use getrandom::{rand_core::{TryRngCore, RngCore}, OsRng};
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// # Usage example
/// ```
/// use getrandom::{rand_core::{TryRngCore, RngCore}, OsRng};
/// # Usage example
///
/// The functionality of this struct is only accessible though its
/// [`TryRngCore`] implementation:
/// ```
/// use getrandom::{OsRng, rand_core::TryRngCore};

We should make it clear that the only way to use OsRng is via TryRngCore.

src/lib.rs Outdated
Comment on lines 44 to 45
#[cfg(feature = "rng")]
pub extern crate 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.

Is there a reason to re-export all of rand_core? Would it make more sense to only re-export TryRngCore as that's the only non-marker trait OsRng implements?

We could then also add additional documentation explaining the re-export:

Suggested change
#[cfg(feature = "rng")]
pub extern crate rand_core;
#[cfg(feature = "rng")]
/// Re-exported base RNG trait from [`rand_core`]
///
pub use rand_core::TryRngCore;

Copy link
Member Author

Choose a reason for hiding this comment

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

@newpavlov convinced me in the past that this is a good general policy, and I agree:

  • It allows downstream crates to access rand_core functionality without explicitly depending on that
  • It does not pretend that TryRngCore is part of getrandom
  • It reduces the chance of people hitting "multiple versions of rand_core" errors

Copy link
Member

Choose a reason for hiding this comment

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

IMO re-exporting rand_core is a must have and should be done by all RNG implementation crates.

@dhardy
Copy link
Member Author

dhardy commented Nov 19, 2025

Thanks for moving this forward @josephlr. I think I addressed your concerns (except as commented).

/// [`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?

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)?

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants