1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#![feature(ptr_metadata)]
//! https://internals.rust-lang.org/t/storing-the-size-in-the-box/15005/3?u=cad97

use std::ops::{Deref, DerefMut};

use std::{marker::PhantomData, ptr};

/// # Example
///
/// ```
/// # #![feature(ptr_metadata, type_name_of_val)] use indyn::*; use std::{any::Any, marker::PhantomData, ptr};
/// let b: Box<Indyn<dyn Any>> = Box::new(indyn!(0usize; as dyn Any));
/// println!("type_name: {}", std::any::type_name_of_val(&b));    // alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
/// println!("size_of  : {}", std::mem::size_of_val(&b));         // 16
///
/// let thin = erasable::erase(ptr::NonNull::new(Box::into_raw(b)).unwrap());
/// println!("type_name: {}", std::any::type_name_of_val(&thin)); // core::ptr::non_null::NonNull<erasable::priv_in_pub::Erased>
/// println!("size_of  : {}", std::mem::size_of_val(&thin));      // 8
///
/// let b: Box<Indyn<dyn Any>> = unsafe { Box::from_raw(Indyn::unerase(thin).as_ptr()) };
/// println!("type_name: {}", std::any::type_name_of_val(&b));    // alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
/// println!("size_of  : {}", std::mem::size_of_val(&b));         // 16
///
/// dbg!(b.downcast_ref::<usize>());
/// ```
#[repr(C)]
pub struct Indyn<Dyn: ?Sized, T: ?Sized = Dyn> {
    #[doc(hidden)]
    pub phantom: PhantomData<Dyn>,
    #[doc(hidden)]
    pub metadata: <Dyn as ptr::Pointee>::Metadata,
    #[doc(hidden)]
    pub inner: T,
}

impl<Dyn: ?Sized> Indyn<Dyn> {
    /// This can't be an implementation of [`erasable::Erasable`] because of the blanket impl for sized `T` :crying:
    pub unsafe fn unerase(this: erasable::ErasedPtr) -> ptr::NonNull<Self> {
        let metadata = ptr::read::<<Dyn as ptr::Pointee>::Metadata>(this.as_ptr() as *mut _);
        let this: *mut Dyn = ptr::from_raw_parts_mut(this.as_ptr() as *mut _, metadata);
        ptr::NonNull::new_unchecked(this as *mut Indyn<Dyn>)
    }
}

impl<Dyn: ?Sized, T: ?Sized> Deref for Indyn<Dyn, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.inner
    }
}

impl<Dyn: ?Sized, T: ?Sized> DerefMut for Indyn<Dyn, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.inner
    }
}

#[macro_export]
macro_rules! indyn {
    ($t:expr; as $d:ty) => {{
        let t = $t;
        let p: &$d = &t;
        Indyn {
            phantom: PhantomData,
            metadata: ptr::metadata(p),
            inner: t,
        }
    }};
}