indyn/lib.rs
1#![feature(ptr_metadata)]
2//! https://internals.rust-lang.org/t/storing-the-size-in-the-box/15005/3?u=cad97
3
4use std::ops::{Deref, DerefMut};
5
6use std::{marker::PhantomData, ptr};
7
8/// # Example
9///
10/// ```
11/// # #![feature(ptr_metadata, type_name_of_val)] use indyn::*; use std::{any::Any, marker::PhantomData, ptr};
12/// let b: Box<Indyn<dyn Any>> = Box::new(indyn!(0usize; as dyn Any));
13/// println!("type_name: {}", std::any::type_name_of_val(&b)); // alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
14/// println!("size_of : {}", std::mem::size_of_val(&b)); // 16
15///
16/// let thin = erasable::erase(ptr::NonNull::new(Box::into_raw(b)).unwrap());
17/// println!("type_name: {}", std::any::type_name_of_val(&thin)); // core::ptr::non_null::NonNull<erasable::priv_in_pub::Erased>
18/// println!("size_of : {}", std::mem::size_of_val(&thin)); // 8
19///
20/// let b: Box<Indyn<dyn Any>> = unsafe { Box::from_raw(Indyn::unerase(thin).as_ptr()) };
21/// println!("type_name: {}", std::any::type_name_of_val(&b)); // alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
22/// println!("size_of : {}", std::mem::size_of_val(&b)); // 16
23///
24/// dbg!(b.downcast_ref::<usize>());
25/// ```
26#[repr(C)]
27pub struct Indyn<Dyn: ?Sized, T: ?Sized = Dyn> {
28 #[doc(hidden)]
29 pub phantom: PhantomData<Dyn>,
30 #[doc(hidden)]
31 pub metadata: <Dyn as ptr::Pointee>::Metadata,
32 #[doc(hidden)]
33 pub inner: T,
34}
35
36impl<Dyn: ?Sized> Indyn<Dyn> {
37 /// This can't be an implementation of [`erasable::Erasable`] because of the blanket impl for sized `T` :crying:
38 pub unsafe fn unerase(this: erasable::ErasedPtr) -> ptr::NonNull<Self> {
39 let metadata = ptr::read::<<Dyn as ptr::Pointee>::Metadata>(this.as_ptr() as *mut _);
40 let this: *mut Dyn = ptr::from_raw_parts_mut(this.as_ptr() as *mut _, metadata);
41 ptr::NonNull::new_unchecked(this as *mut Indyn<Dyn>)
42 }
43}
44
45impl<Dyn: ?Sized, T: ?Sized> Deref for Indyn<Dyn, T> {
46 type Target = T;
47 fn deref(&self) -> &T {
48 &self.inner
49 }
50}
51
52impl<Dyn: ?Sized, T: ?Sized> DerefMut for Indyn<Dyn, T> {
53 fn deref_mut(&mut self) -> &mut T {
54 &mut self.inner
55 }
56}
57
58#[macro_export]
59macro_rules! indyn {
60 ($t:expr; as $d:ty) => {{
61 let t = $t;
62 let p: &$d = &t;
63 Indyn {
64 phantom: PhantomData,
65 metadata: ptr::metadata(p),
66 inner: t,
67 }
68 }};
69}