Skip to content

Instantly share code, notes, and snippets.

@Sgeo
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sgeo/c42c4c2b5bcdf8c91d5a to your computer and use it in GitHub Desktop.
Save Sgeo/c42c4c2b5bcdf8c91d5a to your computer and use it in GitHub Desktop.
HList implementation with macro that allows production of Contains<T>
#![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