Rc<Vec<u8>> should impl AsRef<[u8]>

Cursor wants an AsRef<[u8]>, I have a Rc<Vec<u8>>.

There’s an impl<T> AsRef<T> for Rc<T>. It seems like there should also be a impl AsRef for Rc<Vec>`.

With this, I can do:

let v = Rc::new(vec!());
let c = Cursor::new(v.clone());

Anything wrong with that?

I don’t think that there should be a problem with adding this impl.

For now, can you make use wrapper type?

struct ShareVec<T>(Rc<Vec<T>>);

impl<T> AsRef<[T]> for ShareVec<T> {
    fn as _ref(&self) -> &[T] {
        self.as_slice()
    }
}

fn main() {
    let v = Rc::new(vec!());
    let c = Cursor::new(v.clone());
}

Unfortunately, the generic forwarding implementation conflicts.

impl<T: ?Sized> AsRef<T> for Rc<T> {
    fn as_ref(&self) -> &T { &**self }
}

impl<AR: ?Sized, T: ?Sized> AsRef<T> for Rc<AR>
where AR: AsRef<T>,
{
    fn as_ref(&self) -> &T { &(**self.as_ref()) }
}

If you don’t need the cursor to be ref-counted, then you can do Cursor::new(&*rc_vec_u8).

That’s a pity. CAD97. But logically AsRef<[u8]> should be implemented. I’m more interested in correcting std than my own code (as my own code is now “optimal”).

Unfortunately, the whole point of the Rc was to be reference counted to avoid having to copy the vector.

Is there a reason to have an Rc<Vec<u8>> in the first place, considering Rc disallows mutable access? It seems more reasonable to me to convert your vector to Rc<[T]> via From right from the start.

let v: Rc<[YourType]> = vec!().into();
let c = Cursor::new(v.clone());
2 Likes

You can use Rc to do a simple Clone on Write by using make_mut

Ah, that’s fair. Yeah, in this case the double indirection does foil any attempt to use just one as_ref(), I’ve had this issue before, too.

As far as I can tell it’s also impossible to make an Rc<[T]> without having two copies of the slice data exist simultaneously at some point, making it useless for the seemingly ideal use case of data that is dozens of gigabytes large. Rc<Vec<T>> doesn’t have this problem.

(Basically, no matter how you try to create an Rc<[T]>, at some point you require a [T] so that the length is known, and then there must be a (&[T]) -> Rc<[T]> allocation and memcpy to embed the refcounts)

1 Like

I’m not sure I understand. There is an impl From<Vec<T>> for Rc<[T]> in std – surely that would avoid copying?

Click the view source button right next to it and you’ll see that the only thing it avoids is a T: Clone bound.

(you can believe me when I say I was pretty disappointed to find this out!)

2 Likes

Oh, I see, the issue is that the Rc has to allocate space for the control block containing the strong & weak refcounts. That is a really subtle performance pitfall imo. But in any case, thank you for explaining this to me and sorry for the noise.

1 Like