Why is there no PinRc, PinArc, etc?


#1

Why is ther PinBox but not equivalents for Rc and Arc, or for that matter Vec?


#2

You’re very lucky, @withoutboats posted a sort of reply for this just a few hours ago:

(EDIT: Although it doesn’t cover Vec, I don’t think it’s possible to have a collection of pinned objects similar to Vec, you could probably have some form of bucket allocated linked list as an alternative though).


#3

Nice! I like it.

That actually could potentially add some support for Vec as well, with something like:

impl<T> From<Vec<T>> for Pin<Vec<T>> {
    fn from(pointer: Vec<T>) -> Pin<Vec<T>> {
        unsafe { Pin::new_unchecked(pointer) }
    }
}

impl<P, T> Pin<P>
where
    P: DerefMut<Target = [T]>,
{
    pub fn index_pin<'a, I>(&'a mut self, idx: I) -> Pin<&'a mut I::Output> 
    where 
        I: SliceIndex<[T]>,
        T: 'a
    {
        unsafe {Pin::new_unchecked(&mut self.pointer[idx]) }
    }
}

Of course once you’ve moved the Vec into a Pin, you can’t add or remove elements, since that would move the contents. (So maybe it should be impl<T> From<Vec<T>> for Pin<Box<[T]>> instead?)


#4

I think this would be written

let vec: Vec<_>;
vec.into_boxed_slice()
   .pin()

There’s no reason to support a pin over Vec specifically since Vec can’t be used to pin its contents. (As pushing would move its contents.)


#5

Except that you can’t call all the methods like push since you don’t have a &mut Vec. I’m pretty sure that @tmccombs is right:

impl<T> From<Vec<T>> for Pin<Vec<T>> { /* ... */ }

is valid (using @withoutboats’s new API). I don’t think this should be restricted to Box<[T]>, since Vec can provide a lot more, in addition to not requiring a reallocation on creation. Going through the list of methods (just those on Vec, not those on []), it seems to me that clear, truncate, and set_len should work without modification on Pin<Vec> and push, append, resize, resize_with, resize_default, and extend_from_slice can work if they are modified to return errors instead of reallocating when the Vec is at capacity.

It definitely is a more niche use case, and I don’t think it would ever be possible to justify a standalone PinVec type in the standard library, but this is one of my favorite aspects of @withoutboats’s new API: it allows for these more obscure cases without extra work.


#6

So in effect Pin<Vec<_>> would be a Vec<_> that never reallocated (grows bigger)? That actually seems useful separate from the pinning of its contents, though maybe not as useful as a stack vector.

You could implement an interpreter using a Pin<Vec<Byte>> as the stack, and an attempt to reallocate would be a stack overflow, and since the contents are pinned, references are sound. This sounds simultaneously silly, pointless, and fun.


#7

Yes, though it occurs to me that it would actually be valid (if useless? you could just get a new Vec) to reallocate the Vec when it is empty.