There's currently no way to access trait implementation vtable for generic types in stable rust from base type (i.e. not a fat pointer).
Specialization allows this with default implementations. But I wonder whether it will be stable in the upcoming 5 years, if even, given the number of requirements and edge-cases a stable implementation has to satisfy.
In the meantime, having a stable intrinsic function, that can be deprecated once the specialization lands, would help a lot in cases where those vtables need to be accessed.
The following code works for storing drop glue in stable:
type DropFn = fn(*mut ());
const fn drop_fn<T>() -> DropFn {
if core::mem::needs_drop::<T>() {
|ptr: *mut ()| unsafe { core::ptr::drop_in_place(ptr as *mut T) }
} else {
|_: *mut ()| {}
}
}
I'd like to be able to write a similar function for Display
, but it's not possible. I can't implement default Display
without specialization, nor match Option<DisplayFn>
at runtime.
So, while it's perfectly clear how specialization will help, it currently doesn't and I'd rather avoid making a library require nightly just to use unsound/incomplete features.
What are your oppinons on introducing a function like:
/// Returns pointer to trait implementation vtable in the local compilation unit, if one exists.
const fn trait_vtable<T: Sized + 'static, Trait: ?Sized + 'static>() -> Option<const*>;
The 'static
lifetimes can be parameterized at a later point to allow for more uses.
That would allow code like:
impl Display for MybDisplayWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(vtable) = intrinsics::trait_vtable::<Self, dyn Display>() {
let d: &dyn Display = unsafe {
let inner_ptr: *const () = self.data;
std::mem::transmute((inner_ptr, vtable))
};
d.fmt(f)
} else {
f.write_str("Opaque")
}
}
}