1use alloc::boxed::Box;
2use core::any::TypeId;
3use core::mem::{self, MaybeUninit};
4use core::ptr;
5
6#[cfg(feature = "unstable-debug")]
7use core::any;
8
9pub struct Any {
10 value: Value,
11 drop: unsafe fn(&mut Value),
12 type_id: TypeId,
13
14 #[cfg(feature = "unstable-debug")]
16 type_name: &'static str,
17}
18
19union Value {
20 ptr: *mut (),
21 inline: [MaybeUninit<usize>; 2],
22}
23
24fn is_small<T>() -> bool {
25 mem::size_of::<T>() <= mem::size_of::<Value>()
26 && mem::align_of::<T>() <= mem::align_of::<Value>()
27}
28
29impl Any {
30 pub(crate) unsafe fn new<T>(t: T) -> Self {
41 let value: Value;
42 let drop: unsafe fn(&mut Value);
43 let type_id = typeid::of::<T>();
44
45 if is_small::<T>() {
46 let mut inline = [MaybeUninit::uninit(); 2];
47 unsafe { ptr::write(inline.as_mut_ptr().cast::<T>(), t) };
48 value = Value { inline };
49 unsafe fn inline_drop<T>(value: &mut Value) {
50 unsafe { ptr::drop_in_place(value.inline.as_mut_ptr().cast::<T>()) }
51 }
52 drop = inline_drop::<T>;
53 } else {
54 let ptr = Box::into_raw(Box::new(t)).cast::<()>();
55 value = Value { ptr };
56 unsafe fn ptr_drop<T>(value: &mut Value) {
57 mem::drop(unsafe { Box::from_raw(value.ptr.cast::<T>()) });
58 }
59 drop = ptr_drop::<T>;
60 };
61
62 Any {
63 value,
64 drop,
65 type_id,
66 #[cfg(feature = "unstable-debug")]
67 type_name: any::type_name::<T>(),
68 }
69 }
70
71 pub(crate) unsafe fn take<T>(mut self) -> T {
73 if self.type_id != typeid::of::<T>() {
74 self.invalid_cast_to::<T>();
75 }
76
77 if is_small::<T>() {
78 let ptr = unsafe { self.value.inline.as_mut_ptr().cast::<T>() };
79 let value = unsafe { ptr::read(ptr) };
80 mem::forget(self);
81 value
82 } else {
83 let ptr = unsafe { self.value.ptr.cast::<T>() };
84 let box_t = unsafe { Box::from_raw(ptr) };
85 mem::forget(self);
86 *box_t
87 }
88 }
89
90 #[cfg(not(feature = "unstable-debug"))]
91 fn invalid_cast_to<T>(&self) -> ! {
92 panic!("invalid cast; enable `unstable-debug` feature to debug");
93 }
94
95 #[cfg(feature = "unstable-debug")]
96 fn invalid_cast_to<T>(&self) -> ! {
97 let from = self.type_name;
98 let to = any::type_name::<T>();
99 panic!("invalid cast: {} to {}", from, to);
100 }
101}
102
103impl Drop for Any {
104 fn drop(&mut self) {
105 unsafe { (self.drop)(&mut self.value) }
106 }
107}