gist/fizzbuzz/types/main.rs

285 lines
7.1 KiB
Rust

#![recursion_limit = "1024"]
#![feature(specialization)]
use std::marker::PhantomData;
trait Num { fn render() -> u64; }
struct Zero;
impl Num for Zero { fn render() -> u64 { 0 } }
struct Succ<I: Num>(PhantomData<I>);
impl<I: Num> Num for Succ<I> { fn render() -> u64 { <I>::render() + 1 } }
trait Char { fn render() -> char; }
struct S0 {} impl Char for S0 { fn render() -> char { '0' } }
struct S1 {} impl Char for S1 { fn render() -> char { '1' } }
struct S2 {} impl Char for S2 { fn render() -> char { '2' } }
struct S3 {} impl Char for S3 { fn render() -> char { '3' } }
struct S4 {} impl Char for S4 { fn render() -> char { '4' } }
struct S5 {} impl Char for S5 { fn render() -> char { '5' } }
struct S6 {} impl Char for S6 { fn render() -> char { '6' } }
struct S7 {} impl Char for S7 { fn render() -> char { '7' } }
struct S8 {} impl Char for S8 { fn render() -> char { '8' } }
struct S9 {} impl Char for S9 { fn render() -> char { '9' } }
struct SF {} impl Char for SF { fn render() -> char { 'F' } }
struct Si {} impl Char for Si { fn render() -> char { 'i' } }
struct Sz {} impl Char for Sz { fn render() -> char { 'z' } }
struct SB {} impl Char for SB { fn render() -> char { 'B' } }
struct Su {} impl Char for Su { fn render() -> char { 'u' } }
struct Snl {} impl Char for Snl { fn render() -> char { '\n' } }
trait String { fn render(); }
struct SEmpty {} impl String for SEmpty { fn render() {} }
struct SCons<F: Char, R: String>(PhantomData<F>, PhantomData<R>);
impl<F: Char, R: String> String for SCons<F, R> {
fn render() {
print!("{}", <F>::render());
<R>::render();
}
}
struct SBadEval {}
impl String for SBadEval { fn render() { print!("BAD EVAL"); } }
trait StringifiedImpl: Num {
type Result: String;
}
impl<N: Num> StringifiedImpl for N {
default type Result = SBadEval;
}
impl StringifiedImpl for Zero {
type Result = SCons<S0, SEmpty>;
}
impl<N: Num> StringifiedImpl for Succ<N> {
type Result = <<N as StringifiedImpl>::Result as StringIncrement>::Result;
}
trait Stringified: Num {
type Result: String;
}
impl<N: Num> Stringified for N {
type Result = <<N as StringifiedImpl>::Result as Rev>::Result;
}
trait StringIncrement: String {
type Result: String;
}
impl StringIncrement for SEmpty {
type Result = SCons<S1, SEmpty>;
}
impl<S: String> StringIncrement for S {
default type Result = SBadEval;
}
impl<S: String> StringIncrement for SCons<S0, S> {
type Result = SCons<S1, S>;
}
impl<S: String> StringIncrement for SCons<S1, S> {
type Result = SCons<S2, S>;
}
impl<S: String> StringIncrement for SCons<S2, S> {
type Result = SCons<S3, S>;
}
impl<S: String> StringIncrement for SCons<S3, S> {
type Result = SCons<S4, S>;
}
impl<S: String> StringIncrement for SCons<S4, S> {
type Result = SCons<S5, S>;
}
impl<S: String> StringIncrement for SCons<S5, S> {
type Result = SCons<S6, S>;
}
impl<S: String> StringIncrement for SCons<S6, S> {
type Result = SCons<S7, S>;
}
impl<S: String> StringIncrement for SCons<S7, S> {
type Result = SCons<S8, S>;
}
impl<S: String> StringIncrement for SCons<S8, S> {
type Result = SCons<S9, S>;
}
impl<S: String + StringIncrement> StringIncrement for SCons<S9, S> {
type Result = SCons<S0, <S as StringIncrement>::Result>;
}
trait App<S: String>: String {
type Result: String;
}
impl<S: String, T: String> App<S> for T {
default type Result = SBadEval;
}
impl<S: String> App<S> for SEmpty {
type Result = S;
}
impl<S: String, F: Char, R: String> App<S> for SCons<F, R> {
type Result = SCons<F, <R as App<S>>::Result>;
}
trait Rev: String {
type Result: String;
}
impl<S: String> Rev for S {
default type Result = SBadEval;
}
impl Rev for SEmpty {
type Result = SEmpty;
}
impl<F: Char, R: String> Rev for SCons<F, R> {
type Result = <R as App<SCons<F, SEmpty>>>::Result;
}
trait ModResult { fn render(); }
struct ModBadEval {} impl ModResult for ModBadEval { fn render() { println!("mod bad eval"); } }
struct Mod {} impl ModResult for Mod { fn render() { println!("mod"); } }
struct Modnt {} impl ModResult for Modnt { fn render() { println!("not mod"); } }
trait NumMod3: Num {
type Result: ModResult;
}
impl<T: Num> NumMod3 for T {
default type Result = ModBadEval;
}
impl NumMod3 for Zero {
type Result = Mod;
}
impl NumMod3 for Succ<Zero> {
type Result = Modnt;
}
impl NumMod3 for Succ<Succ<Zero>> {
type Result = Modnt;
}
impl<T: Num> NumMod3 for Succ<Succ<Succ<T>>> {
type Result = <T as NumMod3>::Result;
}
trait NumMod5: Num {
type Result: ModResult;
}
impl<T: Num> NumMod5 for T {
default type Result = ModBadEval;
}
impl NumMod5 for Zero {
type Result = Mod;
}
impl NumMod5 for Succ<Zero> {
type Result = Modnt;
}
impl NumMod5 for Succ<Succ<Zero>> {
type Result = Modnt;
}
impl NumMod5 for Succ<Succ<Succ<Zero>>> {
type Result = Modnt;
}
impl NumMod5 for Succ<Succ<Succ<Succ<Zero>>>> {
type Result = Modnt;
}
impl<T: Num> NumMod5 for Succ<Succ<Succ<Succ<Succ<T>>>>> {
type Result = <T as NumMod5>::Result;
}
trait FizzbuzzStringified: Num {
type Result: String;
}
trait FbstrHelper<Mod3: ModResult, Mod5: ModResult>: Num {
type Result: String;
}
impl<T: Num, Mod3: ModResult, Mod5: ModResult> FbstrHelper<Mod3, Mod5> for T {
default type Result = SBadEval;
}
impl<T: Num> FbstrHelper<Modnt, Modnt> for T {
type Result = <T as Stringified>::Result;
}
impl<T: Num> FbstrHelper<Mod, Modnt> for T {
type Result = SCons<SF, SCons<Si, SCons<Sz, SCons<Sz, SEmpty>>>>;
}
impl<T: Num> FbstrHelper<Modnt, Mod> for T {
type Result = SCons<SB, SCons<Su, SCons<Sz, SCons<Sz, SEmpty>>>>;
}
impl<T: Num> FbstrHelper<Mod, Mod> for T {
type Result = SCons<SF, SCons<Si, SCons<Sz, SCons<Sz, SCons<SB, SCons<Su, SCons<Sz, SCons<Sz, SEmpty>>>>>>>>;
}
impl<T: Num> FizzbuzzStringified for T {
type Result = <T as FbstrHelper<<T as NumMod3>::Result, <T as NumMod5>::Result>>::Result;
}
trait Added<S: Num>: Num {
type Result: Num;
}
impl<T: Num, S: Num> Added<S> for T {
default type Result = S;
}
impl<S: Num> Added<S> for Zero {
type Result = S;
}
impl<T: Num, S: Num> Added<S> for Succ<T> {
type Result = Succ<<T as Added<S>>::Result>;
}
trait FizzbuzzProgram: Num {
type Result: String;
}
impl<T: Num> FizzbuzzProgram for T {
default type Result = SBadEval;
}
impl FizzbuzzProgram for Zero {
type Result = SEmpty;
}
impl<T: Num> FizzbuzzProgram for Succ<T> {
type Result = <<<T as FizzbuzzProgram>::Result as App<<Succ<T> as FizzbuzzStringified>::Result>>::Result as App<SCons<Snl, SEmpty>>>::Result;
}
fn main() {
type One = Succ<Zero>;
type Two = Succ<One>;
type Four = <Two as Added<Two>>::Result;
type Eight = <Four as Added<Four>>::Result;
type Sixteen = <Eight as Added<Eight>>::Result;
type Five = <Four as Added<One>>::Result;
type Ten = <Five as Added<Five>>::Result;
type Thirty = <<<Sixteen as Added<Eight>>::Result as Added<Four>>::Result as Added<Two>>::Result;
type OneHundred = <<<Thirty as Added<Thirty>>::Result as Added<Thirty>>::Result as Added<Ten>>::Result;
<OneHundred as FizzbuzzProgram>::Result::render();
}