diff --git a/Cargo.toml b/Cargo.toml index b5044c3061..83cb89310e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd"] [dependencies] zerocopy-derive = { version = "=0.8.0-alpha.5", path = "zerocopy-derive", optional = true } +getrandom = { version = "0.2", optional = true } # The "associated proc macro pattern" ensures that the versions of zerocopy and # zerocopy-derive remain equal, even if the 'derive' feature isn't used. diff --git a/src/lib.rs b/src/lib.rs index 555922d70d..bd06df5af9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2513,6 +2513,40 @@ pub unsafe trait FromBytes: FromZeros { Ref::<_, Unalign>::new_unaligned_from_suffix(bytes) .map(|(_, r)| r.read().into_inner()) } + + /// Generate random value of `Self` using OS randomness source + /// (see the table in the [`getrandom`] crate docs for more information). + /// + /// # Examples + /// ``` + /// # fn main() -> Result<(), getrandom::Error> { + /// use zerocopy::FromBytes; + /// + /// let seed = u32::getrandom()?; + /// let key: [u8; 16] = FromBytes::getrandom()?; + /// # Ok(()) } + /// ``` + #[cfg(feature = "getrandom")] + #[inline] + fn getrandom() -> Result + where + Self: Sized, + { + 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 ptr: *mut MaybeUninit = value.as_mut_ptr().cast(); + let size = core::mem::size_of::(); + let uninit_bytes = core::slice::from_raw_parts_mut(ptr, size); + getrandom::getrandom_uninit(uninit_bytes)?; + }; + // SAFETY: when `getrandom_uninit` returns `Ok` all bytes in `uninit_bytes` + // (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() }) + } } /// Analyzes whether a type is [`IntoBytes`].