It appears I may have backed myself into a corner, actually:
#![feature(ptr_metadata)]
use {
erasable::Erasable,
std::{marker::PhantomData, ptr},
};
#[repr(C)]
pub struct Indyn<Dyn: ?Sized, T: ?Sized = Dyn> {
phantom: PhantomData<Dyn>,
metadata: <Dyn as ptr::Pointee>::Metadata,
inner: T,
}
unsafe impl<Dyn: ?Sized> Erasable for Indyn<Dyn> {
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>)
}
const ACK_1_1_0: bool = true;
}
This works, and miri is happy to accept it.
Example
macro_rules! indyn {
($t:expr; as $d:ty) => {{
let t = $t;
let p: &$d = &t;
Indyn {
phantom: PhantomData,
metadata: ptr::metadata(p),
inner: t,
}
}};
}
fn main() {
let b: Box<Indyn<dyn Any>> = Box::new(indyn!(0usize; as dyn Any));
println!("type_name: {}", std::any::type_name_of_val(&b));
println!("size_of : {}", std::mem::size_of_val(&b));
let thin = erasable::erase(ptr::NonNull::new(Box::into_raw(b)).unwrap());
println!("type_name: {}", std::any::type_name_of_val(&thin));
println!("size_of : {}", std::mem::size_of_val(&thin));
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));
println!("size_of : {}", std::mem::size_of_val(&b));
dbg!(b.downcast_ref::<usize>());
}
type_name: alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
size_of : 16
type_name: core::ptr::non_null::NonNull<erasable::priv_in_pub::Erased>
size_of : 8
type_name: alloc::boxed::Box<indyn::Indyn<dyn core::any::Any>>
size_of : 16
[src\main.rs:63] b.downcast_ref::<usize>() = Some(
0,
)
Unfortunately...
error[E0119]: conflicting implementations of trait `erasable::Erasable` for type `Indyn<_>`
--> src\main.rs:17:1
|
17 | unsafe impl<Dyn: ?Sized> Erasable for Indyn<Dyn> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `erasable`:
- impl<T> Erasable for T;
the blanket impl of Erasable
for any sized T
conflicts with the specific impl for Indyn
. I still stand by the blanket impl, so I guess arbitrary DST metadata support for erasable::Thin
will need to wait for both ptr_metadata
and min_specialization
(I'm sorry-not-sorry; Indyn
is a pun on "linline")