#![feature(target_feature, asm, platform_intrinsics)]
extern crate rand;
use rand::Rng;
use std::result::Result;
mod util;
extern "platform-intrinsic" {
fn x86_rdrand16_step() -> (u16, i32);
fn x86_rdrand32_step() -> (u32, i32);
fn x86_rdrand64_step() -> (u64, i32);
fn x86_rdseed16_step() -> (u16, i32);
fn x86_rdseed32_step() -> (u32, i32);
fn x86_rdseed64_step() -> (u64, i32);
}
macro_rules! loop_rand {
($f:ident) => {
loop {
unsafe {
let (val, succ) = ($f)();
if succ != 0 { return val; }
}
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum Error {
UnsupportedProcessor
}
impl ::std::error::Error for Error {
fn description(&self) -> &str {
match self {
&Error::UnsupportedProcessor => "processor does not support the instruction",
}
}
}
impl ::std::fmt::Display for Error {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match self {
&Error::UnsupportedProcessor => write!(f, "processor does not support the instruction")
}
}
}
impl From<Error> for ::std::io::Error {
fn from(e: Error) -> ::std::io::Error {
::std::io::Error::new(::std::io::ErrorKind::Other, format!("{}", e))
}
}
#[derive(Clone, Copy)]
pub struct RdRand(());
impl RdRand {
pub fn new() -> Result<RdRand, Error> {
if util::has_rdrand() {
return Ok(RdRand(()));
} else {
return Err(Error::UnsupportedProcessor);
}
}
#[target_feature="+rdrnd"]
pub fn next_u16(&self) -> u16 {
loop_rand!(x86_rdrand16_step);
}
}
impl Rng for RdRand {
#[target_feature="+rdrnd"]
fn next_u32(&mut self) -> u32 {
loop_rand!(x86_rdrand32_step);
}
#[target_feature="+rdrnd"]
fn next_u64(&mut self) -> u64 {
loop_rand!(x86_rdrand64_step);
}
}
#[derive(Clone, Copy)]
pub struct RdSeed(());
impl RdSeed {
pub fn new() -> Result<RdSeed, Error> {
if util::has_rdseed() {
return Ok(RdSeed(()));
} else {
return Err(Error::UnsupportedProcessor);
}
}
#[target_feature="+rdseed"]
pub fn next_u16(&self) -> u16 {
loop_rand!(x86_rdseed16_step);
}
}
impl Rng for RdSeed {
#[target_feature="+rdseed"]
fn next_u32(&mut self) -> u32 {
loop_rand!(x86_rdseed32_step);
}
#[target_feature="+rdseed"]
fn next_u64(&mut self) -> u64 {
loop_rand!(x86_rdseed64_step);
}
}
#[test]
fn rdrand_works() {
let _ = RdRand::new().map(|mut r| {
r.next_u32();
r.next_u64();
});
}
#[test]
fn rdseed_works() {
let _ = RdSeed::new().map(|mut r| {
r.next_u32();
r.next_u64();
});
}