dynamic_enum/
lib.rs

1use std::any::{Any, TypeId};
2use std::mem::transmute;
3
4#[derive(Default, Copy, Clone)]
5pub struct Dynum;
6
7pub trait DynumAdd<N: Any> {
8    type Next;
9    fn add(self, x: N) -> Self::Next;
10}
11
12pub trait DynumGet {
13    fn get<X: Any>(&self) -> &X;
14    fn get_mut<X: Any>(&mut self) -> &mut X;
15}
16
17#[derive(Default)]
18pub struct DynumPair<T: Any, N: DynumGet + Any> {
19    head: T,
20    next: N,
21}
22
23impl<U: DynumGet + Any, N: Any> DynumAdd<N> for U {
24    type Next = DynumPair<N, Self>;
25    #[inline(always)]
26    fn add(self, x: N) -> Self::Next {
27        DynumPair {
28            head: x,
29            next: self,
30        }
31    }
32}
33
34impl<T: Any, U: DynumGet + Any> DynumGet for DynumPair<T, U> {
35    #[inline(always)]
36    fn get<X: Any>(&self) -> &X {
37        let (tid, xid): (u64, u64) = unsafe { transmute((TypeId::of::<T>(), TypeId::of::<X>())) };
38        if tid == xid {
39            unsafe { transmute(&self.head) }
40        } else {
41            self.next.get::<X>()
42        }
43    }
44    #[inline(always)]
45    fn get_mut<X: Any>(&mut self) -> &mut X {
46        let (tid, xid): (u64, u64) = unsafe { transmute((TypeId::of::<T>(), TypeId::of::<X>())) };
47        if tid == xid {
48            unsafe { transmute(&mut self.head) }
49        } else {
50            self.next.get_mut::<X>()
51        }
52    }
53}
54
55impl DynumGet for Dynum {
56    #[inline(always)]
57    fn get<X: Any>(&self) -> &X {
58        panic!("get: Unregistered type")
59    }
60    #[inline(always)]
61    fn get_mut<X: Any>(&mut self) -> &mut X {
62        panic!("get_mut: Unregistered type")
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    #[test]
70    fn it_works() {
71        let a = Dynum.add(0u32).add(2i32);
72        assert_eq!(a.get::<i32>(), &2);
73    }
74
75    #[test]
76    #[should_panic]
77    fn it_panics() {
78        let a = Dynum.add(0u32).add(2i32);
79        a.get::<i64>();
80    }
81}