Skip to content

Instantly share code, notes, and snippets.

@habnabit
Last active February 20, 2016 00:16
Show Gist options
  • Save habnabit/4d7f1fb31417f341f2f4 to your computer and use it in GitHub Desktop.
Save habnabit/4d7f1fb31417f341f2f4 to your computer and use it in GitHub Desktop.
#![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