There has been some interest in using self: &Rc<Self>
and self: &Arc<Self>
as method receivers. The idea is that the method doesn’t always need to take the Rc/Arc
by value, so instead you take a reference to it, and then the method can clone the Arc/Rc
if it needs to extend its lifetime.
The problem is that you can’t perform dynamic dispatch with an &Rc<Self>
, and so such methods cannot be called on a &Rc/Arc<dyn Trait>
.
Here is a potential solution: introduce a new type that can be created from an &Rc<T>
or &Arc<T>
. It’s just a copy of the pointer, but has the lifetime of the reference it was created from, so the Rc/Arc
cannot be modified during its lifetime. For example:
struct Borrowed<'a, T: 'a + ?Sized> {
ptr: NonNull<RcBox<T>>,
_marker: PhantomData<&'a T>,
}
impl<'a, T: ?Sized> Clone for Borrowed<'a, T> {
fn clone(&self) -> Self {
Self {
ptr: self.ptr,
_marker: PhantomData,
}
}
}
impl<'a, T: ?Sized> Copy for Borrowed<'a, T> {}
impl<T: ?Sized> Rc<T> {
fn borrow<'a>(&'a self) -> Borrowed<'a, T> {
Borrowed {
ptr: self.ptr,
_marker: PhantomData,
}
}
}
impl<'a, T: ?Sized> Borrowed<'a, T> {
// poor method name, I know
fn clone(self) -> Rc<T> {
// TODO
// increment the counter, return an Rc just like `<Rc as Clone>::clone` does
}
}
impl<'a, T: ?Sized, U: ?Sized> CoerceUnsized<Borrowed<'a, U>> for Borrowed<'a, T>
where
T: Unsize<U>,
{}
impl<'a, T: ?Sized, U: ?Sized> DispatchFromDyn<Borrowed<'a, U>> for Borrowed<'a, T>
where
T: Unsize<U>,
{}
impl<'a, T: ?Sized> Deref for Borrowed<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &(*self.ptr.as_ptr()).value }
}
}