Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Well-typed (ish) HLists and named tuples in Rust, with const generics
use std::marker::PhantomData;
pub trait Ix { }
pub trait HList { }
pub trait Ixed<T, N> {
fn get(&self) -> &T;
fn get_mut(&mut self) -> &mut T;
}
pub struct Z;
impl Ix for Z { }
pub struct S<N> {
_marker: PhantomData<N>,
}
impl<N: Ix> Ix for S<N> { }
#[derive(Debug, Copy, Clone)]
pub struct HNil;
impl HList for HNil { }
#[derive(Debug, Copy, Clone)]
pub struct HCons<T, Tail> {
pub head: T,
pub tail: Tail,
}
impl<T, Tail: HList> HList for HCons<T, Tail> { }
impl<T, Tail> Ixed<T, Z> for HCons<T, Tail> {
fn get(&self) -> &T {
&self.head
}
fn get_mut(&mut self) -> &mut T {
&mut self.head
}
}
impl<T, U, N, Tail: Ixed<U, N>> Ixed<U, S<N>> for HCons<T, Tail> {
fn get(&self) -> &U {
self.tail.get()
}
fn get_mut(&mut self) -> &mut U {
self.tail.get_mut()
}
}
#[inline]
pub fn get<N, T, H: Ixed<T, N>>(hlist: &H) -> &T {
hlist.get()
}
#[inline]
pub fn get_mut<N, T, H: Ixed<T, N>>(hlist: &mut H) -> &mut T {
hlist.get_mut()
}
use crate::hlist::*;
#[derive(Debug, Copy, Clone)]
pub struct Named<T, const NAME: &'static str>(T);
#[derive(Debug, Copy, Clone)]
pub struct NamedTuple<H>(H);
impl NamedTuple<HNil> {
pub fn new() -> Self {
NamedTuple(HNil)
}
}
impl<H: HList> NamedTuple<H> {
pub fn add<const NAME: &'static str, T>(self, val: T) -> NamedTuple<HCons<Named<T, NAME>, H>> {
NamedTuple(HCons {
head: Named(val),
tail: self.0,
})
}
}
#[inline]
pub fn nt_get<T, H, N, const NAME: &'static str>(nt: &NamedTuple<H>) -> &T
where H: Ixed<Named<T, NAME>, N> {
&nt.0.get().0
}
#[inline]
pub fn nt_get_mut<T, H, N, const NAME: &'static str>(nt: &mut NamedTuple<H>) -> &mut T
where H: Ixed<Named<T, NAME>, N> {
&mut nt.0.get_mut().0
}
#![feature(const_generics)]
mod hlist;
use hlist::*;
mod namedtuple;
use namedtuple::*;
fn main() {
let mut xs = HCons {
head: 3,
tail: HCons {
head: "yo",
tail: HNil,
}
};
dbg!(get::<Z, _, _>(&xs));
dbg!(get::<S<Z>, _, _>(&xs));
*get_mut::<_, &str, _>(&mut xs) = "joe";
dbg!(get::<S<Z>, _, _>(&xs));
let nt = NamedTuple::new();
let nt = nt.add::<"first_name", _>("joe");
let nt = nt.add::<"last_name", _>("smith");
let mut nt = nt.add::<"age", _>(32);
dbg!(nt_get::<_, _, _, "first_name">(&nt));
*nt_get_mut::<_, _, _, "first_name">(&mut nt) = "bob";
dbg!(nt_get::<_, _, _, "first_name">(&nt));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.