Skip to content

Instantly share code, notes, and snippets.

@stevenblenkinsop
Forked from anonymous/playground.rs
Last active September 27, 2015 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenblenkinsop/0ec1f79f7e0cd51f0269 to your computer and use it in GitHub Desktop.
Save stevenblenkinsop/0ec1f79f7e0cd51f0269 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
use std::marker::PhantomData;
struct Nothing;
#[allow(dead_code)]
struct Neg;
struct Zero<T: Num>(PhantomData<T>);
struct One<T: Num>(PhantomData<T>);
pub use num::Num;
mod num {
use super::{Nothing, One, Zero, Neg};
pub trait Num {
fn eval() -> i32;
}
impl<T: Num> Num for Zero<T> {
fn eval() -> i32 { T::eval() * 2 }
}
impl<T: Num> Num for One<T> {
fn eval() -> i32 { T::eval() * 2 + 1 }
}
impl Num for Nothing {
fn eval() -> i32 { 0 }
}
impl Num for Neg {
fn eval() -> i32 { -1 }
}
}
trait Something: Num {}
impl<T: Num> Something for Zero<T> {}
impl<T: Num> Something for One<T> {}
type NumZero = Nothing;
type NumOne = One<Nothing>;
type NumTwo = Zero<NumOne>;
type NumThree = Add<NumOne, NumTwo>;
type NumFour = Add<NumTwo, NumTwo>;
type NumFive = Add<NumTwo, NumThree>;
type NumEight = Add<NumFour, NumFour>;
type Add<X, Y> where X: AddImpl<Y>, Y: Num = <X as AddImpl<Y>>::Out;
type Sub<X, Y> where X: SubImpl<Y>, Y: Num = <X as SubImpl<Y>>::Out;
type Mul<X, Y> where X: MulImpl<Y>, Y: Num = <X as MulImpl<Y>>::Out;
// type Div<X, Y> where X: DivImpl<Y>, Y: Num = <X as DivImpl<Y>>::Out;
pub use add::AddImpl;
mod add {
use super::{Num, Nothing, Something, Zero, One, NumZero, NumOne};
pub trait AddImpl<Y: Num>: Num {
type Out: Num;
}
impl<X, Y> AddImpl<Y> for X
where Y: Num,
X: AddCarryImpl<Y, NumZero> {
type Out = X::Out;
}
pub trait AddCarryImpl<Y: Num, C: Num>: Num {
type Out: Num;
}
impl<X, Y> AddCarryImpl<Zero<Y>, NumZero> for Zero<X>
where Y: Num,
X: AddCarryImpl<Y, NumZero> {
type Out = Zero<X::Out>;
}
impl<X, Y> AddCarryImpl<One<Y>, NumZero> for Zero<X>
where Y: Num,
X: AddCarryImpl<Y, NumZero> {
type Out = One<X::Out>;
}
impl<X, Y> AddCarryImpl<Zero<Y>, NumOne> for Zero<X>
where Y: Num,
X: AddCarryImpl<Y, NumZero> {
type Out = One<X::Out>;
}
impl<X, Y> AddCarryImpl<One<Y>, NumOne> for Zero<X>
where Y: Num,
X: AddCarryImpl<Y, NumOne> {
type Out = Zero<X::Out>;
}
impl<X, Y> AddCarryImpl<Zero<Y>, NumZero> for One<X>
where Y: Num,
X: AddCarryImpl<Y, NumZero> {
type Out = One<X::Out>;
}
impl<X, Y> AddCarryImpl<One<Y>, NumZero> for One<X>
where Y: Num,
X: AddCarryImpl<Y, NumOne> {
type Out = Zero<X::Out>;
}
impl<X, Y> AddCarryImpl<Zero<Y>, NumOne> for One<X>
where Y: Num,
X: AddCarryImpl<Y, NumOne> {
type Out = Zero<X::Out>;
}
impl<X, Y> AddCarryImpl<One<Y>, NumOne> for One<X>
where Y: Num,
X: AddCarryImpl<Y, NumOne> {
type Out = One<X::Out>;
}
impl<X: Num> AddCarryImpl<Nothing, NumZero> for X {
type Out = X;
}
impl<X> AddCarryImpl<Nothing, NumOne> for X
where X: AddCarryImpl<NumOne, NumZero> {
type Out = X::Out;
}
impl<Y>AddCarryImpl<Y, NumZero> for Nothing
where Y: Something {
type Out = Y;
}
impl<Y> AddCarryImpl<Y, NumOne> for Nothing
where Y: AddCarryImpl<NumOne, NumZero> + Something {
type Out = Y::Out;
}
}
pub use sub::SubImpl;
mod sub {
use super::{Num, Zero, One, Neg, NumZero, NumOne, Something};
pub trait SubImpl<Y: Num>: Num {
type Out: Num;
}
impl<X: Num, Y: Num> SubImpl<Y> for X
where X: SubImplCarry<Y, NumZero> {
type Out = X::Out;
}
trait SubImplCarry<Y: Num, C: Num>: Num {
type Out: Num;
}
impl<X: Num> SubImplCarry<NumZero, NumZero> for X {
type Out = X;
}
impl<X: Something> SubImplCarry<NumZero, NumOne> for X
where X: SubImplCarry<NumOne, NumZero> {
type Out = X::Out;
}
impl SubImplCarry<NumZero, NumOne> for NumZero {
type Out = Neg;
}
impl<Y: Num, R: Num> SubImplCarry<Zero<Y>, NumZero> for NumZero
where NumZero: SubImplCarry<Y, NumZero, Out=R> {
type Out = Zero<R>;
}
impl<Y: Num, R: Num> SubImplCarry<One<Y>, NumZero> for NumZero
where NumZero: SubImplCarry<Y, NumOne, Out=R> {
type Out = One<R>;
}
impl<Y: Num, R: Num> SubImplCarry<Zero<Y>, NumOne> for NumZero
where NumZero: SubImplCarry<Y, NumOne, Out=R> {
type Out = One<R>;
}
impl<Y: Num, R: Num> SubImplCarry<One<Y>, NumOne> for NumZero
where NumZero: SubImplCarry<Y, NumOne, Out=R> {
type Out = Zero<R>;
}
impl<X: Num, Y: Num> SubImplCarry<Zero<Y>, NumZero> for Zero<X>
where X: SubImplCarry<Y, NumZero> {
type Out = Zero<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<One<Y>, NumZero> for Zero<X>
where X: SubImplCarry<Y, NumOne> {
type Out = One<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<One<Y>, NumOne> for Zero<X>
where X: SubImplCarry<Y, NumOne> {
type Out = Zero<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<Zero<Y>, NumOne> for Zero<X>
where X: SubImplCarry<Y, NumOne> {
type Out = One<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<Zero<Y>, NumZero> for One<X>
where X: SubImplCarry<Y, NumZero> {
type Out = One<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<One<Y>, NumZero> for One<X>
where X: SubImplCarry<Y, NumZero> {
type Out = Zero<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<One<Y>, NumOne> for One<X>
where X: SubImplCarry<Y, NumOne> {
type Out = One<X::Out>;
}
impl<X: Num, Y: Num> SubImplCarry<Zero<Y>, NumOne> for One<X>
where X: SubImplCarry<Y, NumZero> {
type Out = Zero<X::Out>;
}
}
pub use mul::MulImpl;
mod mul {
use super::{Num, Nothing, Zero, One, Add, Mul, AddImpl};
pub trait MulImpl<Y: Num>: Num {
type Out: Num;
}
impl<X: Num, Y: Num> MulImpl<Zero<Y>> for X
where Zero<X>: MulImpl<Y> {
type Out = Mul<Zero<X>, Y>;
}
impl<X: Num, Y: Num, Z> MulImpl<One<Y>> for X
where Zero<X>: MulImpl<Y, Out=Z>,
Z: AddImpl<X> {
type Out = Add<Z, X>;
}
impl<X: Num> MulImpl<Nothing> for X {
type Out = Nothing;
}
}
fn main() {
println!("{}", <Add<NumEight, NumThree>>::eval());
println!("{}", <Sub<Add<Mul<NumEight, NumEight>, NumThree>, NumEight>>::eval());
println!("{}", <Sub<NumOne, Add<NumEight, NumFive>>>::eval());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment