1use alloc::boxed::Box;
2#[cfg(any(debug_assertions, miri))]
3use core::any::{self, TypeId};
4use core::mem;
5
6pub(crate) struct ErasedValue {
7 ptr: *mut (),
8 drop: unsafe fn(*mut ()),
9 #[cfg(any(debug_assertions, miri))]
10 type_id: TypeId,
11 #[cfg(any(debug_assertions, miri))]
12 type_name: &'static str,
13}
14
15impl ErasedValue {
16 pub(crate) unsafe fn new<T>(value: T) -> Self {
17 ErasedValue {
18 ptr: Box::into_raw(Box::new(value)).cast(),
19 drop: {
20 unsafe fn drop<T>(ptr: *mut ()) {
21 let _ = unsafe { Box::from_raw(ptr.cast::<T>()) };
22 }
23 drop::<T>
24 },
25 #[cfg(any(debug_assertions, miri))]
26 type_id: typeid::of::<T>(),
27 #[cfg(any(debug_assertions, miri))]
28 type_name: any::type_name::<T>(),
29 }
30 }
31
32 pub(crate) unsafe fn take<T>(self) -> T {
33 #[cfg(any(debug_assertions, miri))]
34 assert_eq!(
35 self.type_id,
36 typeid::of::<T>(),
37 "ErasedValue mismatch: {} vs {}",
38 self.type_name,
39 any::type_name::<T>(),
40 );
41
42 let b = unsafe { Box::from_raw(self.ptr.cast::<T>()) };
43 mem::forget(self);
44 *b
45 }
46}
47
48impl Drop for ErasedValue {
49 fn drop(&mut self) {
50 unsafe { (self.drop)(self.ptr) }
51 }
52}