]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/type-macros-hlist.rs
Changed issue number to 36105
[rust.git] / src / test / run-pass / type-macros-hlist.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![feature(type_macros)]
12
13 use std::ops::*;
14
15 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
16 struct Nil;
17  // empty HList
18 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
19 struct Cons<H, T: HList>(H, T);
20  // cons cell of HList
21
22  // trait to classify valid HLists
23 trait HList { }
24 impl HList for Nil { }
25 impl <H, T: HList> HList for Cons<H, T> { }
26
27 // term-level macro for HLists
28 macro_rules! hlist({  } => { Nil } ; { $ head : expr } => {
29                    Cons ( $ head , Nil ) } ; {
30                    $ head : expr , $ ( $ tail : expr ) , * } => {
31                    Cons ( $ head , hlist ! ( $ ( $ tail ) , * ) ) } ;);
32
33 // type-level macro for HLists
34 macro_rules! HList({  } => { Nil } ; { $ head : ty } => {
35                    Cons < $ head , Nil > } ; {
36                    $ head : ty , $ ( $ tail : ty ) , * } => {
37                    Cons < $ head , HList ! ( $ ( $ tail ) , * ) > } ;);
38
39 // nil case for HList append
40 impl <Ys: HList> Add<Ys> for Nil {
41     type
42     Output
43     =
44     Ys;
45
46     fn add(self, rhs: Ys) -> Ys { rhs }
47 }
48
49 // cons case for HList append
50 impl <Rec: HList + Sized, X, Xs: HList, Ys: HList> Add<Ys> for Cons<X, Xs>
51  where Xs: Add<Ys, Output = Rec> {
52     type
53     Output
54     =
55     Cons<X, Rec>;
56
57     fn add(self, rhs: Ys) -> Cons<X, Rec> { Cons(self.0, self.1 + rhs) }
58 }
59
60 // type macro Expr allows us to expand the + operator appropriately
61 macro_rules! Expr({ ( $ ( $ LHS : tt ) + ) } => { Expr ! ( $ ( $ LHS ) + ) } ;
62                   { HList ! [ $ ( $ LHS : tt ) * ] + $ ( $ RHS : tt ) + } => {
63                   < Expr ! ( HList ! [ $ ( $ LHS ) * ] ) as Add < Expr ! (
64                   $ ( $ RHS ) + ) >> :: Output } ; {
65                   $ LHS : tt + $ ( $ RHS : tt ) + } => {
66                   < Expr ! ( $ LHS ) as Add < Expr ! ( $ ( $ RHS ) + ) >> ::
67                   Output } ; { $ LHS : ty } => { $ LHS } ;);
68
69 // test demonstrating term level `xs + ys` and type level `Expr!(Xs + Ys)`
70 fn main() {
71     fn aux<Xs: HList, Ys: HList>(xs: Xs, ys: Ys) -> Expr!(Xs + Ys) where
72      Xs: Add<Ys> {
73         xs + ys
74     }
75
76     let xs: HList!(& str , bool , Vec < u64 >) =
77         hlist!("foo" , false , vec ! [  ]);
78     let ys: HList!(u64 , [ u8 ; 3 ] , (  )) =
79         hlist!(0 , [ 0 , 1 , 2 ] , (  ));
80
81     // demonstrate recursive expansion of Expr!
82     let zs:
83             Expr!((
84                   HList ! [ & str ] + HList ! [ bool ] + HList ! [ Vec < u64 >
85                   ] ) + ( HList ! [ u64 ] + HList ! [ [ u8 ; 3 ] , (  ) ] ) +
86                   HList ! [  ]) = aux(xs, ys);
87     assert_eq!(zs , hlist ! [
88                "foo" , false , vec ! [  ] , 0 , [ 0 , 1 , 2 ] , (  ) ])
89 }