`Rc/Arc::Borrowed`: An object-safe version of `&Rc<T>`/`&Arc<T>`

This has nothing to do with arbitrary_self_type, but DispatchFromDyn.

The problem is &Rc<dyn Trait> currently is a thin pointer like &(Rc<()>, &VTable), not the regular DST representation like (&Rc<()>, &VTable). (There is no unsize-coercion relationship to &Rc<dyn Trait> from &Rc<T>.) So the compiler cannot generate the code for dynamic dispatch of &Rc<dyn Trait> like the single-pointer counterpart:

fn dyn_dispatch_rc(self: Rc<dyn Trait>) {
    let vtable = metadata(self);
    (vtable.fptr_of_method)(self as Rc<()>)
    // ^ just take the thin pointer part
}

However I don’t think we need to introduce this Borrow type either. We just need to tell the compiler to obtain the vtable not from the pointer itself, but its pointee:

fn dyn_dispatch_rc_ref(self: &Rc<dyn Trait>) {
    let vtable = metadata(*self); // ← take *self not self
    (vtable.fptr_of_method)(self as &Rc<()>)
    // object-slice the metadata part away
}

Meaning we should change the DispatchFromDyn trait to require a method to extract the vtable

trait DispatchFromDyn<T> {
    fn vtable(dst: &T) -> &'static VTable;
}
impl DispatchFromDyn<Rc<U>> for Rc<T> {
    fn vtable(dst: &Rc<U>) -> &'static VTable {
        metadata(*dst)
    }
}
impl DispatchFromDyn<&Rc<U>> for &Rc<T> {
    fn vtable(dst: &&Rc<U>) -> &'static VTable {
        metadata(**dst)
    }
}
2 Likes