use hybrid_array::{Array, ArraySize};
use rand_core::{CryptoRng, TryCryptoRng};
#[cfg(feature = "getrandom")]
use crate::RngError;
pub trait Generate: Sized {
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error>;
fn from_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
let Ok(ret) = Self::try_from_rng(rng);
ret
}
#[cfg(feature = "getrandom")]
fn try_generate() -> Result<Self, RngError> {
Self::try_from_rng(&mut sys_rng::SysRng)
}
#[cfg(feature = "getrandom")]
fn generate() -> Self {
Self::try_generate().expect("RNG failure")
}
}
impl Generate for u32 {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
rng.try_next_u32()
}
}
impl Generate for u64 {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
rng.try_next_u64()
}
}
impl<const N: usize> Generate for [u8; N] {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
let mut ret = [0u8; N];
rng.try_fill_bytes(&mut ret)?;
Ok(ret)
}
}
impl<U: ArraySize> Generate for Array<u8, U> {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
let mut ret = Self::default();
rng.try_fill_bytes(&mut ret)?;
Ok(ret)
}
}
impl<U: ArraySize> Generate for Array<u32, U> {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
Self::try_from_fn(|_| rng.try_next_u32())
}
}
impl<U: ArraySize> Generate for Array<u64, U> {
#[inline]
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
Self::try_from_fn(|_| rng.try_next_u64())
}
}
#[cfg(feature = "getrandom")]
mod sys_rng {
use getrandom::Error;
use rand_core::{TryCryptoRng, TryRngCore};
#[derive(Clone, Copy, Debug, Default)]
pub struct SysRng;
impl TryRngCore for SysRng {
type Error = Error;
#[inline]
fn try_next_u32(&mut self) -> Result<u32, Error> {
getrandom::u32()
}
#[inline]
fn try_next_u64(&mut self) -> Result<u64, Error> {
getrandom::u64()
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
getrandom::fill(dest)
}
}
impl TryCryptoRng for SysRng {}
}