| // run-pass |
| use std::ops::*; |
| |
| #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| struct Nil; |
| // empty HList |
| #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| struct Cons<H, T: HList>(H, T); |
| // cons cell of HList |
| |
| // trait to classify valid HLists |
| trait HList { } |
| impl HList for Nil { } |
| impl <H, T: HList> HList for Cons<H, T> { } |
| |
| // term-level macro for HLists |
| macro_rules! hlist({ } => { Nil } ; { $ head : expr } => { |
| Cons ( $ head , Nil ) } ; { |
| $ head : expr , $ ( $ tail : expr ) , * } => { |
| Cons ( $ head , hlist ! ( $ ( $ tail ) , * ) ) } ;); |
| |
| // type-level macro for HLists |
| macro_rules! HList({ } => { Nil } ; { $ head : ty } => { |
| Cons < $ head , Nil > } ; { |
| $ head : ty , $ ( $ tail : ty ) , * } => { |
| Cons < $ head , HList ! ( $ ( $ tail ) , * ) > } ;); |
| |
| // nil case for HList append |
| impl <Ys: HList> Add<Ys> for Nil { |
| type |
| Output |
| = |
| Ys; |
| |
| fn add(self, rhs: Ys) -> Ys { rhs } |
| } |
| |
| // cons case for HList append |
| impl <Rec: HList + Sized, X, Xs: HList, Ys: HList> Add<Ys> for Cons<X, Xs> |
| where Xs: Add<Ys, Output = Rec> { |
| type |
| Output |
| = |
| Cons<X, Rec>; |
| |
| fn add(self, rhs: Ys) -> Cons<X, Rec> { Cons(self.0, self.1 + rhs) } |
| } |
| |
| // type macro Expr allows us to expand the + operator appropriately |
| macro_rules! Expr({ ( $ ( $ LHS : tt ) + ) } => { Expr ! ( $ ( $ LHS ) + ) } ; |
| { HList ! [ $ ( $ LHS : tt ) * ] + $ ( $ RHS : tt ) + } => { |
| < Expr ! ( HList ! [ $ ( $ LHS ) * ] ) as Add < Expr ! ( |
| $ ( $ RHS ) + ) >> :: Output } ; { |
| $ LHS : tt + $ ( $ RHS : tt ) + } => { |
| < Expr ! ( $ LHS ) as Add < Expr ! ( $ ( $ RHS ) + ) >> :: |
| Output } ; { $ LHS : ty } => { $ LHS } ;); |
| |
| // test demonstrating term level `xs + ys` and type level `Expr!(Xs + Ys)` |
| fn main() { |
| fn aux<Xs: HList, Ys: HList>(xs: Xs, ys: Ys) -> Expr!(Xs + Ys) where |
| Xs: Add<Ys> { |
| xs + ys |
| } |
| |
| let xs: HList!(& str , bool , Vec < u64 >) = |
| hlist!("foo" , false , vec ! [ ]); |
| let ys: HList!(u64 , [ u8 ; 3 ] , ( )) = |
| hlist!(0 , [ 0 , 1 , 2 ] , ( )); |
| |
| // demonstrate recursive expansion of Expr! |
| let zs: |
| Expr!(( |
| HList ! [ & str ] + HList ! [ bool ] + HList ! [ Vec < u64 > |
| ] ) + ( HList ! [ u64 ] + HList ! [ [ u8 ; 3 ] , ( ) ] ) + |
| HList ! [ ]) = aux(xs, ys); |
| assert_eq!(zs , hlist ! [ |
| "foo" , false , vec ! [ ] , 0 , [ 0 , 1 , 2 ] , ( ) ]) |
| } |