|
| 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; // empty HList |
| 17 | +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 18 | +struct Cons<H, T: HList>(H, T); // cons cell of HList |
| 19 | + |
| 20 | +// trait to classify valid HLists |
| 21 | +trait HList {} |
| 22 | +impl HList for Nil {} |
| 23 | +impl<H, T: HList> HList for Cons<H, T> {} |
| 24 | + |
| 25 | +// term-level macro for HLists |
| 26 | +macro_rules! hlist { |
| 27 | + {} => { Nil }; |
| 28 | + { $head:expr } => { Cons($head, Nil) }; |
| 29 | + { $head:expr, $($tail:expr),* } => { Cons($head, hlist!($($tail),*)) }; |
| 30 | +} |
| 31 | + |
| 32 | +// type-level macro for HLists |
| 33 | +macro_rules! HList { |
| 34 | + {} => { Nil }; |
| 35 | + { $head:ty } => { Cons<$head, Nil> }; |
| 36 | + { $head:ty, $($tail:ty),* } => { Cons<$head, HList!($($tail),*)> }; |
| 37 | +} |
| 38 | + |
| 39 | +// nil case for HList append |
| 40 | +impl<Ys: HList> Add<Ys> for Nil { |
| 41 | + type Output = Ys; |
| 42 | + |
| 43 | + fn add(self, rhs: Ys) -> Ys { |
| 44 | + rhs |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +// cons case for HList append |
| 49 | +impl<Rec: HList + Sized, X, Xs: HList, Ys: HList> Add<Ys> for Cons<X, Xs> where |
| 50 | + Xs: Add<Ys, Output = Rec>, |
| 51 | +{ |
| 52 | + type Output = Cons<X, Rec>; |
| 53 | + |
| 54 | + fn add(self, rhs: Ys) -> Cons<X, Rec> { |
| 55 | + Cons(self.0, self.1 + rhs) |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +// type macro Expr allows us to expand the + operator appropriately |
| 60 | +macro_rules! Expr { |
| 61 | + { ( $($LHS:tt)+ ) } => { Expr!($($LHS)+) }; |
| 62 | + { HList ! [ $($LHS:tt)* ] + $($RHS:tt)+ } => { |
| 63 | + <Expr!(HList![$($LHS)*]) as Add<Expr!($($RHS)+)>>::Output |
| 64 | + }; |
| 65 | + { $LHS:tt + $($RHS:tt)+ } => { <Expr!($LHS) as Add<Expr!($($RHS)+)>>::Output }; |
| 66 | + { $LHS:ty } => { $LHS }; |
| 67 | +} |
| 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) |
| 72 | + where Xs: Add<Ys> { |
| 73 | + xs + ys |
| 74 | + } |
| 75 | + |
| 76 | + let xs: HList![&str, bool, Vec<u64>] = hlist!["foo", false, vec![]]; |
| 77 | + let ys: HList![u64, [u8; 3], ()] = hlist![0, [0, 1, 2], ()]; |
| 78 | + |
| 79 | + // demonstrate recursive expansion of Expr! |
| 80 | + let zs: Expr!((HList![&str] + HList![bool] + HList![Vec<u64>]) + |
| 81 | + (HList![u64] + HList![[u8; 3], ()]) + |
| 82 | + HList![]) |
| 83 | + = aux(xs, ys); |
| 84 | + assert_eq!(zs, hlist!["foo", false, vec![], 0, [0, 1, 2], ()]) |
| 85 | +} |
| 86 | + |
0 commit comments