Last active
August 29, 2015 14:19
-
-
Save Sgeo/c42c4c2b5bcdf8c91d5a to your computer and use it in GitHub Desktop.
HList implementation with macro that allows production of Contains<T>
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
#![allow(dead_code)] | |
struct HNil; | |
struct HCons<H, T> { | |
head: H, | |
tail: T | |
} | |
trait Contains<A> { | |
fn get(&self) -> &A; | |
fn get_mut(&mut self) -> &mut A; | |
} | |
macro_rules! hlist_type_internal { | |
($hlist_name:ident, $hlist_current:ty, $th:ty, $($tr:ty,)*) => { | |
hlist_type_internal!($hlist_name, HCons<$th, $hlist_current>, $($tr,)*); | |
}; | |
($hlist_name:ident, $hlist_current:ty,) => { | |
type $hlist_name = $hlist_current; | |
} | |
} | |
macro_rules! hlist_type { | |
($hlist:ident) => {hlist_type_internal!($hlist, HNil,)}; | |
($hlist:ident, $($types:ty),* ) => {hlist_type_internal!($hlist, HNil, $($types,)*);} | |
} | |
// First argument is the HList type | |
// Remaining arguments are the types that the HList contains. | |
// Starting from the tail of the HList. | |
macro_rules! generate_hlist_contains { | |
($hlist:ty) => {{}}; | |
($hlist:ty,) => {{}}; | |
($hlist:ty, $last:ty, $($init:ty,)*) => {{ | |
impl Contains<$last> for $hlist { | |
#[allow(unused_variables)] | |
fn get(&self) -> &$last { | |
let cur_cell = self; | |
$( | |
let head: &$init = &cur_cell.head; // Only used to refer to $init | |
let cur_cell = &cur_cell.tail; | |
)* | |
&cur_cell.head | |
} | |
#[allow(unused_variables)] | |
fn get_mut(&mut self) -> &mut $last { | |
let cur_cell = self; | |
$( | |
let head: &$init = &cur_cell.head; | |
let cur_cell = &mut cur_cell.tail; | |
)* | |
&mut cur_cell.head | |
} | |
} | |
generate_hlist_contains!($hlist, $($init,)*); | |
}} | |
} | |
macro_rules! generate_hlist { | |
($($types:ty),*) => {{ | |
hlist_type!(TheHList, $($types),*); | |
generate_hlist_contains!(TheHList, $($types,)*); | |
}} | |
} | |
trait HList: Sized { | |
fn insert<A: Sized>(self, a: A) -> HCons<A, Self> { | |
HCons { head: a, tail: self } | |
} | |
} | |
impl HList for HNil {} | |
impl<H, T: HList> HList for HCons<H, T> {} | |
fn main() { | |
generate_hlist!(i32, String); | |
let list = HNil.insert(5i32).insert("hello".to_string()); | |
//hlist_type!(MyHList, i32, String); | |
//generate_hlist_contains!(MyHList, i32, String); | |
//println!("{}", contains::<String, _>(list)); | |
let a: &i32 = list.get(); | |
println!("{}", a); | |
let b: &String = list.get(); | |
println!("{}", b); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment