-
-
Save stevenblenkinsop/0ec1f79f7e0cd51f0269 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
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
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