Skip to main content

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}