Repository: rust
Issue: `impl<T> PointerLike for {Rc,Arc,Weak}<T>` can't exist but should
Labels: C-feature-request,F-dyn_star

The unstable trait `PointerLike` must be implemented for any type which is to be coerced to a [`dyn*` type](https://github.com/rust-lang/rust/issues/102425). However, the only built-in smart pointer type it is currently implemented for is `Box`, and this is a special case in the compiler.

I believe it would be useful for `PointerLike` to be implemented for, among other things, `Rc`, `Arc`, and their corresponding `Weak` types. This would enable use cases such as polymorphic collections like `Vec<dyn* SomeTrait>` where each element consists of a (strong or weak) reference-counted pointer to other data structures, whereas the current available option is `Vec<Box<dyn SomeTrait>>` which results in an inefficient extra allocation and double-indirection for each item.

However, it is currently impossible even to modify the standard library to meet this requirement. This is because the compiler requires that the type implementing `PointerLike` be either primitive or `repr(transparent)`, and types like `Rc` cannot be `repr(transparent)` because they have an allocator field:

```rust
pub struct Rc<
    T: ?Sized,
    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
    ptr: NonNull<RcInner<T>>,
    phantom: PhantomData<RcInner<T>>,
    alloc: A,
}
```

The only non-zero-sized field of `Rc<T>` is `ptr`, but `Rc<T, SomeNonZstAllocator>` is non-zero-sized, which disqualifies the entire `Rc` type from being able to have `repr(transparent)`, and therefore means you can't even implement `PointerLike` for `Rc<T>` = `Rc<T, Global>`.

It seems to me that, therefore, it would be useful to adjust the design of `PointerLike`’s implementation restriction — or of `repr(transparent)`, or something — so that `impl PointerLike<T> for Rc<T>` is possible. `Box` manages to implement `PointerLike` only by way of having been granted a unique “is `Box`” exception. This exception could be generalized to other standard library types, and that would address being able to use `Rc` and friends in `dyn*`, but it would privilege the standard library in a way that has no path to stabilization.

(If `dyn*` settles into being solely an async trait implementation detail and not a language feature, then this entire issue is arguably moot since users won't be getting to write `Vec<dyn* Trait>` at all — but `PointerLike` would still be potentially useful as a trait bound to people trying to solve similar problems in libraries.)

---

For an example of the kind of code I’m interested in writing:

```rust
#![allow(incomplete_features)]
#![feature(pointer_like_trait)]
#![feature(dyn_star)]

use std::cell::Cell;
use std::rc::{Rc, Weak};

pub trait Watcher<T> {
    fn notify(&self, value: &T);
}

pub struct Watched<T> {
    value: T,
    watchers: Vec<dyn* Watcher<T>>,
}

impl<T> Watched<T> {
    pub fn set(&mut self, value: T) {
        self.value = value;
        for watcher in self.watchers.iter() {
            watcher.notify(&self.value);
        }
    }
}

#[repr(transparent)]
struct CopyToCell<T>(Weak<Cell<T>>);
impl<T> core::marker::PointerLike for CopyToCell<T> {}
impl<T: Copy + 'static> Watcher<T> for CopyToCell<T> {
    fn notify(&self, value: &T) {
        if let Some(cell) = self.0.upgrade() {
            cell.set(*value);
        }
    }
}

fn main() {
    let c = Rc::new(Cell::new(0));
    let mut w = Watched {
        value: 0,
        watchers: vec![
            CopyToCell(Rc::downgrade(&c))
        ],
    };
    
    w.set(1);
    assert_eq!(c.get(), 1);
}
```

This code does not compile, but the only reason it does not is that the `PointerLike` implementation is rejected. You can prove this by wrapping the `Weak` in an extra `Box`, and, it will compile and run on current nightly.

---


@rustbot label +F-dyn_star