Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"]
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")))]
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")))]
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>,
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() })
}