1 | /* |
2 | This module generates code to try efficiently convert some arbitrary `T: 'static` into |
3 | a `Internal`. |
4 | */ |
5 | |
6 | #[cfg (feature = "alloc" )] |
7 | use crate::std::string::String; |
8 | |
9 | use crate::ValueBag; |
10 | |
11 | // NOTE: The casts for unsized values (str) are dubious here. To really do this properly |
12 | // we need https://github.com/rust-lang/rust/issues/81513 |
13 | // NOTE: With some kind of const `Any::is<T>` we could do all this at compile-time |
14 | // Older versions of `value-bag` did this, but the infrastructure just wasn't worth |
15 | // the tiny performance improvement |
16 | use crate::std::any::TypeId; |
17 | |
18 | enum Void {} |
19 | |
20 | #[repr (transparent)] |
21 | struct VoidRef<'a>(*const &'a Void); |
22 | |
23 | macro_rules! check_type_ids { |
24 | (&$l:lifetime $v:ident => $( |
25 | $(#[cfg($($cfg:tt)*)])* |
26 | $ty:ty, |
27 | )* |
28 | ) => { |
29 | $( |
30 | $(#[cfg($($cfg)*)])* |
31 | if TypeId::of::<T>() == TypeId::of::<$ty>() { |
32 | // SAFETY: We verify the value is $ty before casting |
33 | let v = unsafe { *($v.0 as *const & $l $ty) }; |
34 | |
35 | return Some(ValueBag::from(v)); |
36 | } |
37 | )* |
38 | $( |
39 | $(#[cfg($($cfg)*)])* |
40 | if TypeId::of::<T>() == TypeId::of::<Option<$ty>>() { |
41 | // SAFETY: We verify the value is Option<$ty> before casting |
42 | let v = unsafe { *($v.0 as *const & $l Option<$ty>) }; |
43 | |
44 | if let Some(v) = v { |
45 | return Some(ValueBag::from(v)); |
46 | } else { |
47 | return Some(ValueBag::empty()); |
48 | } |
49 | } |
50 | )* |
51 | }; |
52 | } |
53 | |
54 | pub(in crate::internal) fn from_any<'v, T: ?Sized + 'static>(value: &'v T) -> Option<ValueBag<'v>> { |
55 | let type_ids = |v: VoidRef<'v>| { |
56 | if TypeId::of::<T>() == TypeId::of::<str>() { |
57 | // SAFETY: We verify the value is str before casting |
58 | let v = unsafe { *(v.0 as *const &'v str) }; |
59 | |
60 | return Some(ValueBag::from(v)); |
61 | } |
62 | |
63 | check_type_ids!( |
64 | &'v v => |
65 | usize, |
66 | u8, |
67 | u16, |
68 | u32, |
69 | u64, |
70 | u128, |
71 | isize, |
72 | i8, |
73 | i16, |
74 | i32, |
75 | i64, |
76 | i128, |
77 | f32, |
78 | f64, |
79 | char, |
80 | bool, |
81 | &'static str, |
82 | // We deal with `str` separately because it's unsized |
83 | // str, |
84 | #[cfg(feature = "alloc" )] |
85 | String, |
86 | ); |
87 | |
88 | None |
89 | }; |
90 | |
91 | (type_ids)(VoidRef(&(value) as *const &'v T as *const &'v Void)) |
92 | } |
93 | |
94 | #[cfg (feature = "owned" )] |
95 | pub(in crate::internal) fn from_owned_any<'a, T: ?Sized + 'static>( |
96 | value: &'a T, |
97 | ) -> Option<ValueBag<'static>> { |
98 | let type_ids = |v: VoidRef<'a>| { |
99 | check_type_ids!( |
100 | &'a v => |
101 | usize, |
102 | u8, |
103 | u16, |
104 | u32, |
105 | u64, |
106 | #[cfg(feature = "inline-i128" )] |
107 | u128, |
108 | isize, |
109 | i8, |
110 | i16, |
111 | i32, |
112 | i64, |
113 | #[cfg(feature = "inline-i128" )] |
114 | i128, |
115 | f32, |
116 | f64, |
117 | char, |
118 | bool, |
119 | ); |
120 | |
121 | None |
122 | }; |
123 | |
124 | (type_ids)(VoidRef(&(value) as *const &'a T as *const &'a Void)) |
125 | } |
126 | |