erased_serde/
any.rs

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    /// For panic messages only. Not used for comparison.
15    #[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    // This is unsafe -- caller must not hold on to the Any beyond the lifetime
31    // of T.
32    //
33    // Example of bad code:
34    //
35    //    let s = "bad".to_owned();
36    //    let a = Any::new(&s);
37    //    drop(s);
38    //
39    // Now `a.as_ref()` and `a.take()` return references to a dead String.
40    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    // This is unsafe -- caller is responsible that T is the correct type.
72    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}