1#![cfg_attr(test, deny(warnings))]
2#![deny(missing_docs)]
3
4extern crate unsafe_any as uany;
14
15use uany::UnsafeAnyExt;
16
17use std::any::{TypeId, Any};
18use std::{fmt, mem};
19
20pub struct Dynamic {
29 id: TypeId,
30 data: Dyn
31}
32
33impl Dynamic {
34 #[inline]
38 pub fn new<T: Any>(val: T) -> Box<Dynamic> {
39 let un_sized = Box::new(Described {
40 id: TypeId::of::<T>(),
41 data: val
42 }) as Box<Described<Dyn>>;
43
44 unsafe { mem::transmute(un_sized) }
45 }
46
47 #[inline]
51 pub fn from_ref<T: Any>(val: &Described<T>) -> &Dynamic {
52 let un_sized = val as &Described<Dyn>;
53 unsafe { mem::transmute(un_sized) }
54 }
55
56 #[inline]
60 pub fn from_mut<T: Any>(val: &mut Described<T>) -> &mut Dynamic {
61 let un_sized = val as &mut Described<Dyn>;
62 unsafe { mem::transmute(un_sized) }
63 }
64
65 #[inline]
67 pub fn id(&self) -> TypeId { self.id }
68
69 #[inline(always)]
71 pub fn is<T: Any>(&self) -> bool {
72 self.id == TypeId::of::<T>()
73 }
74
75 #[inline]
79 pub fn downcast<T: Any>(self: Box<Self>) -> Result<Box<Described<T>>, Box<Self>> {
80 if self.is::<T>() {
81 Ok(unsafe { Box::from_raw(Box::into_raw(self) as *mut Described<T>) })
82 } else {
83 Err(self)
84 }
85 }
86
87 #[inline]
89 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
90 if self.is::<T>() {
91 Some(unsafe { self.data.downcast_ref_unchecked() })
92 } else {
93 None
94 }
95 }
96
97 #[inline]
99 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
100 if self.is::<T>() {
101 Some(unsafe { self.data.downcast_mut_unchecked() })
102 } else {
103 None
104 }
105 }
106}
107
108impl fmt::Debug for Dynamic {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 f.debug_struct("Dynamic")
111 .field("id", &self.id)
112 .field("data", &"{{ dynamically typed value }}")
113 .finish()
114 }
115}
116
117#[derive(Copy, Clone, Debug, PartialEq)]
121pub struct Described<T: ?Sized> {
122 id: TypeId,
125
126 pub data: T
128}
129
130impl<T: Any> Described<T> {
131 #[inline]
133 pub fn new(val: T) -> Described<T> {
134 Described {
135 id: TypeId::of::<T>(),
136 data: val
137 }
138 }
139
140 #[inline]
142 pub fn id(&self) -> TypeId { self.id }
143}
144
145trait Dyn {}
147impl<T> Dyn for T {}
148
149unsafe impl UnsafeAnyExt for Dyn {}
151
152#[cfg(test)]
153mod test {
154 use std::any::TypeId;
155 use {Dynamic, Described};
156
157 struct X(usize);
158 struct Y(usize);
159 struct Z(usize);
160
161 #[test]
162 fn test_downcasting() {
163 let mut x = Dynamic::new(X(1));
164
165 assert!(x.is::<X>());
166 assert!(!x.is::<Y>());
167 assert!(!x.is::<Z>());
168
169 *x.downcast_mut::<X>().unwrap() = X(100);
170 assert_eq!(x.downcast_ref::<X>().unwrap().0, 100);
171
172 let described_x = x.downcast::<X>().unwrap();
173 assert_eq!(described_x.id(), TypeId::of::<X>());
174 assert_eq!(described_x.data.0, 100);
175 }
176
177 #[test]
178 fn test_dynamic_refs() {
179 let described_z = Described::new(Z(1000));
180
181 let z_ref = Dynamic::from_ref(&described_z);
182 assert_eq!(z_ref.downcast_ref::<Z>().unwrap().0, 1000);
183 }
184}
185