feat: support cloning random handles
Add OsRandom::try_clone for fallible duplication of the underlying /dev/urandom file handle, and implement Clone as the infallible convenience form. This gives independent call sites their own OsRandom values without adding interior mutability or shared buffering to the core type. The fallible method is documented as the preferred API when callers need to handle a failed file-handle duplication. Clone mirrors Default by panicking only for the convenience path. Document both cloning forms with doctested examples and add a runnable clone example that uses independent handles for IDs and string helpers. Test Plan: - cargo test - cargo clippy - cargo clippy --benches - cargo clippy --tests - cargo +nightly fmt Refs: IDEAS.md ergonomics backlog
This commit is contained in:
+49
@@ -329,6 +329,35 @@ impl OsRandom {
|
||||
self.devurandom.read_exact(buf)
|
||||
}
|
||||
|
||||
/// Duplicates this handle to `/dev/urandom`.
|
||||
///
|
||||
/// The cloned value has its own [`File`] handle, so separate call sites can
|
||||
/// own independent `OsRandom` values while reading from the same
|
||||
/// operating-system randomness source.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns any I/O error produced while duplicating the underlying file
|
||||
/// handle.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> std::io::Result<()> {
|
||||
/// let mut first = ez_urandom::OsRandom::try_new()?;
|
||||
/// let mut second = first.try_clone()?;
|
||||
///
|
||||
/// let a = first.get_u64()?;
|
||||
/// let b = second.get_u64()?;
|
||||
/// # let _ = (a, b);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn try_clone(&self) -> io::Result<Self> {
|
||||
Ok(Self {
|
||||
devurandom: self.devurandom.try_clone()?,
|
||||
})
|
||||
}
|
||||
|
||||
os_random_get_integer_impls!(
|
||||
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
|
||||
);
|
||||
@@ -353,6 +382,26 @@ impl Default for OsRandom {
|
||||
}
|
||||
}
|
||||
|
||||
/// Duplicates the underlying `/dev/urandom` handle.
|
||||
///
|
||||
/// Prefer [`OsRandom::try_clone`] when the caller should decide how to handle an
|
||||
/// I/O failure while duplicating the file handle.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let rng = ez_urandom::OsRandom::default();
|
||||
/// let mut cloned = rng.clone();
|
||||
/// let value = cloned.get_u32().expect("/dev/urandom read failed");
|
||||
/// # let _ = value;
|
||||
/// ```
|
||||
impl Clone for OsRandom {
|
||||
fn clone(&self) -> Self {
|
||||
self.try_clone()
|
||||
.expect("/dev/urandom handle should be cloneable")
|
||||
}
|
||||
}
|
||||
|
||||
/// Uniform sampling helpers.
|
||||
///
|
||||
/// Range methods use rejection sampling on top of the matching primitive
|
||||
|
||||
Reference in New Issue
Block a user