Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getrandom::value function based on zerocopy::FromBytes #381

Closed
wants to merge 10 commits into from
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ exclude = [".*"]

[dependencies]
cfg-if = "1"
# WARNING: Enabling this dependency bumps MSRV to 1.60
zerocopy = { version = "0.7", optional = true, default-features = false }

# When built as part of libstd
compiler_builtins = { version = "0.1", optional = true }
Expand Down Expand Up @@ -49,7 +51,7 @@ rustc-dep-of-std = [
test-in-browser = []

[package.metadata.docs.rs]
features = ["std", "custom"]
features = ["std", "custom", "zeroize"]
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
rustdoc-args = ["--cfg", "docsrs"]

# workaround for https://github.com/cross-rs/cross/issues/1345
Expand Down
1 change: 0 additions & 1 deletion src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ use core::{mem::MaybeUninit, num::NonZeroU32};
/// [top-level documentation](index.html#custom-implementations) this
/// registration only has an effect on unsupported targets.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
macro_rules! register_custom_getrandom {
($path:path) => {
// TODO(MSRV 1.37): change to unnamed block
Expand Down
1 change: 0 additions & 1 deletion src/error_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(docsrs, doc(cfg(feature = "std")))]
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
extern crate std;

use crate::Error;
Expand Down
36 changes: 35 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,14 @@
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

#[macro_use]
extern crate cfg_if;

#[cfg(feature = "zerocopy")]
pub use zerocopy;

use crate::util::{slice_as_uninit_mut, slice_assume_init_mut};
use core::mem::MaybeUninit;

Expand Down Expand Up @@ -349,3 +352,34 @@ pub fn getrandom_uninit(dest: &mut [MaybeUninit<u8>]) -> 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<T: zerocopy::FromBytes + Sized>() -> Result<T, Error> {
let mut value = MaybeUninit::<T>::uninit();
// SAFETY: it's safe to cast `&mut MaybeUninit<T>` to `&mut [MaybeUninit<u8>]`
// with slice length equal to `size_of::<T>()`. 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<T> as *mut MaybeUninit<u8>,
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
core::mem::size_of::<T>(),
);
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() })
}