diff --git a/Cargo.toml b/Cargo.toml index 790fa2fa..cd6e7088 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ exclude = [".*"] [dependencies] cfg-if = "1" +zerocopy = { version = "0.7", optional = true, default-features = false } # When built as part of libstd compiler_builtins = { version = "0.1", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 6336098b..572abc19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -349,3 +349,34 @@ pub fn getrandom_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error // since it returned `Ok`. Ok(unsafe { slice_assume_init_mut(dest) }) } + +/// Generate a random value of type `T` implementing the [`zerocopy::FromBytes`] trait. +/// +/// # Examples +/// ``` +/// # fn main() -> Result<(), getrandom::Error> { +/// let key: [u8; 16] = getrandom::value()?; +/// let keys: [[u8; 16]; 64] = getrandom::value()?; +/// let random_u32: u32 = getrandom::value()?; +/// let random_u64s: [u64; 100] = getrandom::getrandom_value()?; +/// # Ok(()) } +/// ``` +#[cfg(feature = "zerocopy")] +#[inline] +pub fn value() -> Result { + let mut value = MaybeUninit::::uninit(); + // SAFETY: it's safe to cast `&mut MaybeUninit` to `&mut [MaybeUninit]` + // with slice length equal to `size_of::()`. The compiler will ensure that + // `T` isn't too large. + unsafe { + let as_bytes_mut = core::slice::from_raw_parts_mut( + &mut value as *mut MaybeUninit as *mut MaybeUninit, + core::mem::size_of::(), + ); + getrandom_uninit(as_bytes_mut)?; + }; + // SAFETY: when `getrandom_uninit` returns `Ok` all bytes in `as_bytes_mut` + // (and thus in `value`) are properly initialized. Any bit-sequence is valid + // for `T: FromBytes`, so we can safely execute `assume_init` on `value`. + Ok(unsafe { value.assume_init() }) +}