recursive_variadic/
lib.rs

1//! This is an implementation of variadic templates using recursive generics.
2//! It functions something like a TypeMap, but the optimizer should make getting
3//! and adding values much faster.
4
5use std::any::{Any, TypeId};
6use std::mem;
7
8pub trait Key {
9    type Value: Any;
10}
11
12/// The building block trait for recursive variadics.
13pub trait RecursiveVariadic {
14    /// Try to get the value for N.
15    fn get<N: Key>(&self) -> Option<&N::Value>;
16    /// Try to get the value for N mutably.
17    fn get_mut<N: Key>(&mut self) -> Option<&mut N::Value>;
18    /// Add a key-value pair to this.
19    fn and<N: Key>(self, val: N::Value) -> Entry<N, Self> where Self: Sized {
20        Entry {
21            data: val,
22            parent: self,
23        }
24    }
25    /// Add the default value for N
26    fn and_default<N: Key>(self) -> Entry<N, Self> 
27    where N::Value: Default, Self: Sized {
28        self.and(N::Value::default())
29    }
30}
31
32/// The base case for recursive variadics: no fields.
33pub type Empty = ();
34impl RecursiveVariadic for Empty {
35    fn get<N: Key>(&self) -> Option<&N::Value> { None }
36    fn get_mut<N: Key>(&mut self) -> Option<&mut N::Value> { None }
37}
38
39/// Wraps some field data and a parent, which is either another Entry or Empty
40pub struct Entry<T: Key, R> {
41    data: T::Value,
42    parent: R,
43}
44
45impl<T: Key, R: RecursiveVariadic> RecursiveVariadic for Entry<T, R> {
46    fn get<N: Key>(&self) -> Option<&N::Value> { 
47        if TypeId::of::<N::Value>() == TypeId::of::<T::Value>() {
48            Some(unsafe { mem::transmute(&self.data) })
49        } else {
50            self.parent.get::<N>()
51        }
52    }
53    fn get_mut<N: Key>(&mut self) -> Option<&mut N::Value> { 
54        if TypeId::of::<N::Value>() == TypeId::of::<T::Value>() {
55            Some(unsafe { mem::transmute(&mut self.data) })
56        } else {
57            self.parent.get_mut::<N>()
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use std::any::Any;
65
66    use super::*;
67
68    #[test]
69    fn it_works() {
70        impl Key for i32 { type Value = i32; }
71        impl Key for usize { type Value = Vec<usize>; }
72        impl Key for bool { type Value = bool; }
73        impl Key for &'static str { type Value = &'static str; }
74
75        let mut thing = ().and::<i32>(23).and_default::<usize>().and::<&'static str>("Hello!");
76        thing.get_mut::<usize>().unwrap().push(1);
77        assert!(thing.get::<i32>().is_some());
78        assert!(thing.get::<&'static str>().is_some());
79        assert!(thing.get::<bool>().is_none());
80    }
81}