Last active
February 20, 2016 00:16
-
-
Save habnabit/4d7f1fb31417f341f2f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(unsize, associated_consts, zero_one, core_intrinsics)] | |
extern crate rand; | |
use rand::{Rand, Rng}; | |
use std::boxed::Box; | |
use std::{fmt, num, ops}; | |
use std::marker::{PhantomData, Unsize}; | |
pub trait Arbitrary: Sized + 'static { | |
fn arbitrary<G: Rng>(g: &mut G) -> Self; | |
fn shrink(&self) -> Box<Iterator<Item=Self>> { | |
Box::new(::std::iter::empty()) | |
} | |
} | |
trait Restriction { | |
fn format_name(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{}", unsafe { std::intrinsics::type_name::<Self>() }) | |
} | |
fn is_permitted(&self) -> bool; | |
} | |
trait IsPositiveInteger { | |
fn is_positive_integer(&self) -> bool; | |
} | |
impl Restriction for IsPositiveInteger { | |
fn is_permitted(&self) -> bool { | |
self.is_positive_integer() | |
} | |
} | |
trait IsEven { | |
fn is_even(&self) -> bool; | |
} | |
impl Restriction for IsEven { | |
fn is_permitted(&self) -> bool { | |
self.is_even() | |
} | |
} | |
trait IsDivisibleByThree { | |
fn is_divisible_by_three(&self) -> bool; | |
} | |
impl Restriction for IsDivisibleByThree { | |
fn is_permitted(&self) -> bool { | |
self.is_divisible_by_three() | |
} | |
} | |
trait IsDivisibleByFive { | |
fn is_divisible_by_five(&self) -> bool; | |
} | |
impl Restriction for IsDivisibleByFive { | |
fn is_permitted(&self) -> bool { | |
self.is_divisible_by_five() | |
} | |
} | |
trait RAnd<A: ?Sized + Restriction, B: ?Sized + Restriction> { | |
fn first_permitted(&self) -> bool; | |
fn format_first_name(&self, f: &mut fmt::Formatter) -> fmt::Result; | |
fn second_permitted(&self) -> bool; | |
fn format_second_name(&self, f: &mut fmt::Formatter) -> fmt::Result; | |
} | |
impl<A: ?Sized + Restriction, B: ?Sized + Restriction, T: Unsize<A> + Unsize<B>> RAnd<A, B> for T { | |
fn first_permitted(&self) -> bool { | |
A::is_permitted(self) | |
} | |
fn format_first_name(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
A::format_name(self, f) | |
} | |
fn second_permitted(&self) -> bool { | |
B::is_permitted(self) | |
} | |
fn format_second_name(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
B::format_name(self, f) | |
} | |
} | |
impl<A: ?Sized + Restriction, B: ?Sized + Restriction> Restriction for RAnd<A, B> { | |
fn is_permitted(&self) -> bool { | |
self.first_permitted() && self.second_permitted() | |
} | |
fn format_name(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
try!(self.format_first_name(f)); | |
try!(write!(f, " && ")); | |
self.format_second_name(f) | |
} | |
} | |
#[derive(Clone, PartialEq, Eq)] | |
struct Restricted<R: ?Sized + Restriction, T: Sized + Unsize<R>>(T, PhantomData<R>); | |
impl<R: ?Sized + Restriction, T: fmt::Debug + Sized + Unsize<R>> fmt::Debug for Restricted <R, T> { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
try!(write!(f, "Restricted({:?}, ", self.0)); | |
try!(R::format_name(&self.0, f)); | |
write!(f, ")") | |
} | |
} | |
impl<R: ?Sized + Restriction + 'static, T: Arbitrary + Unsize<R>> Arbitrary for Restricted<R, T> { | |
fn arbitrary<G: Rng>(g: &mut G) -> Restricted<R, T> { | |
loop { | |
let ret = T::arbitrary(&mut *g); | |
if R::is_permitted(&ret) { | |
return Restricted(ret, PhantomData); | |
} | |
} | |
} | |
fn shrink(&self) -> Box<Iterator<Item = Self>> { | |
let iter = Arbitrary::shrink(&self.0) | |
.map(|s| Restricted(s, PhantomData)); | |
Box::new(iter) | |
} | |
} | |
impl<T> IsPositiveInteger for T where T: num::Zero + Ord { | |
fn is_positive_integer(&self) -> bool { | |
*self > T::zero() | |
} | |
} | |
impl<T> IsEven for T where T: Clone + num::Zero + num::One + ops::Add<Output = T> + ops::Rem<Output = T> + Eq { | |
fn is_even(&self) -> bool { | |
let two = T::one() + T::one(); | |
self.clone() % two == T::zero() | |
} | |
} | |
impl<T> IsDivisibleByThree for T where T: Clone + num::Zero + num::One + ops::Add<Output = T> + ops::Rem<Output = T> + Eq { | |
fn is_divisible_by_three(&self) -> bool { | |
let three = T::one() + T::one() + T::one(); | |
self.clone() % three == T::zero() | |
} | |
} | |
impl<T> IsDivisibleByFive for T where T: Clone + num::Zero + num::One + ops::Add<Output = T> + ops::Rem<Output = T> + Eq { | |
fn is_divisible_by_five(&self) -> bool { | |
let five = T::one() + T::one() + T::one() + T::one() + T::one(); | |
self.clone() % five == T::zero() | |
} | |
} | |
impl<T> Arbitrary for T where T: Rand + 'static { | |
fn arbitrary<G: Rng>(g: &mut G) -> T { | |
T::rand(g) | |
} | |
} | |
fn main() { | |
let mut rng = ::rand::thread_rng(); | |
for _ in 0..20 { | |
let i: Restricted<RAnd<IsDivisibleByThree, IsDivisibleByFive>, usize> = Restricted::arbitrary(&mut rng); | |
let j: Restricted<IsEven, usize> = Restricted::arbitrary(&mut rng); | |
println!("i {:?} j {:?}", i, j); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment