fn is_same_type(x: &dyn Trait + 'static, y: &dyn Trait + 'static) -> bool {
let x_vtable = get_vtable(x); // get_vtable: fn(*const Trait) -> *const ()
let y_vtable = get_vtable(y); // currently we can achieve this in nightly via std::raw::TraitObject
x_vtable == y_vtable
}
Would this function be valid? This works off of this assumption: two trait objects refer to the same type if and only if the v-tables inside the trait object are the same (ignoring lifetimes).
If it is valid, could we change the implementation of <dyn Any:>:is::<T>()
to work based off of this.
impl dyn Any + 'static {
pub fn is<T: Any>(&self) -> bool {
let self_vtable = get_vtable(self);
// this is fine because vtables of fat pointers (from trait objects) are always
// well-formed and this is guaranteed, even for null pointers
let t_vtable = get_vtable(std::ptr::null::<T>() as *const dyn Any);
self_vtable == t_vtable
}
}
That way you can use TypeId
as a way to get a coarse measurement of whether the types are the same, but you can check them for sure with <dyn Any>::is::<T>
.
We could even go one step further and add
impl dyn Any + 'static {
pub fn is_same_type(&self, other: &Self) -> bool {
let self_vtable = get_vtable(self);
let other_vtable = get_vtable(other);
self_vtable == other_vtable
}
}
And this would provide some functionality that is missing. Checking if two types are the same without loss of precision due to using TypeId
.
We could guarantee that this always works. But that would require the assumption at the beginning to be true.
Two trait objects refer to the same type if and only if the v-tables inside the trait object are the same (ignoring lifetimes)