/rust/registry/src/index.crates.io-6f17d22bba15001f/erased-serde-0.4.6/src/any.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use alloc::boxed::Box; |
2 | | use core::any::TypeId; |
3 | | use core::mem::{self, MaybeUninit}; |
4 | | use core::ptr; |
5 | | |
6 | | #[cfg(feature = "unstable-debug")] |
7 | | use core::any; |
8 | | |
9 | | pub 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 | | |
19 | | union Value { |
20 | | ptr: *mut (), |
21 | | inline: [MaybeUninit<usize>; 2], |
22 | | } |
23 | | |
24 | 0 | fn is_small<T>() -> bool { |
25 | 0 | mem::size_of::<T>() <= mem::size_of::<Value>() |
26 | 0 | && mem::align_of::<T>() <= mem::align_of::<Value>() |
27 | 0 | } |
28 | | |
29 | | impl 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 | 0 | pub(crate) unsafe fn new<T>(t: T) -> Self { |
41 | 0 | let value: Value; |
42 | 0 | let drop: unsafe fn(&mut Value); |
43 | 0 | let type_id = typeid::of::<T>(); |
44 | 0 |
|
45 | 0 | if is_small::<T>() { |
46 | 0 | let mut inline = [MaybeUninit::uninit(); 2]; |
47 | 0 | unsafe { ptr::write(inline.as_mut_ptr().cast::<T>(), t) }; |
48 | 0 | value = Value { inline }; |
49 | 0 | unsafe fn inline_drop<T>(value: &mut Value) { |
50 | 0 | unsafe { ptr::drop_in_place(value.inline.as_mut_ptr().cast::<T>()) } |
51 | 0 | } |
52 | 0 | drop = inline_drop::<T>; |
53 | 0 | } else { |
54 | 0 | let ptr = Box::into_raw(Box::new(t)).cast::<()>(); |
55 | 0 | value = Value { ptr }; |
56 | 0 | unsafe fn ptr_drop<T>(value: &mut Value) { |
57 | 0 | mem::drop(unsafe { Box::from_raw(value.ptr.cast::<T>()) }); |
58 | 0 | } |
59 | 0 | drop = ptr_drop::<T>; |
60 | 0 | } |
61 | | |
62 | 0 | Any { |
63 | 0 | value, |
64 | 0 | drop, |
65 | 0 | type_id, |
66 | 0 | #[cfg(feature = "unstable-debug")] |
67 | 0 | type_name: any::type_name::<T>(), |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | // This is unsafe -- caller is responsible that T is the correct type. |
72 | 0 | pub(crate) unsafe fn take<T>(mut self) -> T { |
73 | 0 | if self.type_id != typeid::of::<T>() { |
74 | 0 | self.invalid_cast_to::<T>(); |
75 | 0 | } |
76 | 0 |
|
77 | 0 | if is_small::<T>() { |
78 | 0 | let ptr = unsafe { self.value.inline.as_mut_ptr().cast::<T>() }; |
79 | 0 | let value = unsafe { ptr::read(ptr) }; |
80 | 0 | mem::forget(self); |
81 | 0 | value |
82 | | } else { |
83 | 0 | let ptr = unsafe { self.value.ptr.cast::<T>() }; |
84 | 0 | let box_t = unsafe { Box::from_raw(ptr) }; |
85 | 0 | mem::forget(self); |
86 | 0 | *box_t |
87 | | } |
88 | 0 | } |
89 | | |
90 | | #[cfg(not(feature = "unstable-debug"))] |
91 | 0 | fn invalid_cast_to<T>(&self) -> ! { |
92 | 0 | 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 | | |
103 | | impl Drop for Any { |
104 | 0 | fn drop(&mut self) { |
105 | 0 | unsafe { (self.drop)(&mut self.value) } |
106 | 0 | } |
107 | | } |