use std::any::{Any, TypeId};
use std::mem::transmute;
#[derive(Default, Copy, Clone)]
pub struct Dynum;
pub trait DynumAdd<N: Any> {
type Next;
fn add(self, x: N) -> Self::Next;
}
pub trait DynumGet {
fn get<X: Any>(&self) -> &X;
fn get_mut<X: Any>(&mut self) -> &mut X;
}
#[derive(Default)]
pub struct DynumPair<T: Any, N: DynumGet + Any> {
head: T,
next: N,
}
impl<U: DynumGet + Any, N: Any> DynumAdd<N> for U {
type Next = DynumPair<N, Self>;
#[inline(always)]
fn add(self, x: N) -> Self::Next {
DynumPair {
head: x,
next: self,
}
}
}
impl<T: Any, U: DynumGet + Any> DynumGet for DynumPair<T, U> {
#[inline(always)]
fn get<X: Any>(&self) -> &X {
let (tid, xid): (u64, u64) = unsafe { transmute((TypeId::of::<T>(), TypeId::of::<X>())) };
if tid == xid {
unsafe { transmute(&self.head) }
} else {
self.next.get::<X>()
}
}
#[inline(always)]
fn get_mut<X: Any>(&mut self) -> &mut X {
let (tid, xid): (u64, u64) = unsafe { transmute((TypeId::of::<T>(), TypeId::of::<X>())) };
if tid == xid {
unsafe { transmute(&mut self.head) }
} else {
self.next.get_mut::<X>()
}
}
}
impl DynumGet for Dynum {
#[inline(always)]
fn get<X: Any>(&self) -> &X {
panic!("get: Unregistered type")
}
#[inline(always)]
fn get_mut<X: Any>(&mut self) -> &mut X {
panic!("get_mut: Unregistered type")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let a = Dynum.add(0u32).add(2i32);
assert_eq!(a.get::<i32>(), &2);
}
#[test]
#[should_panic]
fn it_panics() {
let a = Dynum.add(0u32).add(2i32);
a.get::<i64>();
}
}