Making custom fat pointer types to behave as &mut

Let's imagine I want to implement efficient read-only SoA fat pointer. It can look like this:

// acts as [&'a [T]; N], but guarantees that
// all slices have the same length
struct Foo<'a, T, const N: usize> {
    ptrs: [*const T; N],
    len: usize,
    _pd: PhantomData<&'a T>,
}

It's quite easy to make it behave as &T by simply deriving Copy for it. But what if we want to work with mutable pointers instead?

struct FooMut<'a, T, const N: usize> {
    ptrs: [*mut T; N],
    len: usize,
    _pd: PhantomData<&'a mut T>,
}

impl<'a, T, const N: usize> FooMut<'a, T, N> {
    fn get_slices(&mut self) -> [&'a mut [T]; N] { .. }
}

Ideally it would be nice to be able to write the following code:

let val: FooMut<u32, 4> = get_foo();
use_foo1(val);
use_foo2(val);

But obviously it will not work, since val gets moved into use_foo1. And we can not implement Copy for FooMut, since it would allow creation of two mutable references pointing to the same memory.

Is it possible to somehow make FooMut behave as &mut? AFAIK the answer is no. How feasible in your opinion would be it to add to the language a marker trait or an attribute, which would make custom types behave as &mut?

We could of course simply pass &mut FooMut<'a, T, N> around, but not only it's a bit cumbersome, but also may result in undesired indirection.

I don't think that's possible since it's not possible to abstract over mutability at this time. But it might be possible to use &mut FooMut.

I don't know if it's possible or not, but if it is, it overwhelmingly likely won't be coming to a stable rust compiler near you before 2023. That's sufficiently far into the future that at the moment you may as well design and write your code with the assumption it will never be possible.

From what I understand, rustc is pretty smart about getting rid of superfluous indirections like &&&str and &mut &mut MyType. But if you really want to know if it will significantly impact the performance of the code, you'll have to profile it with e.g. criterion.

see Some way to simulate `&mut` reborrows in user code · Issue #1403 · rust-lang/rfcs · GitHub

5 Likes

This Stack Overflow question (I answered) asks the same thing.

2 Likes

Btw, there is a stdlib example of this: the Pin<&mut T> pointer type, which features a reborrowing method, <Pin<&mut T>>::as_mut(), which yields a Pin<&'reborrow mut T> out of a &'reborrow mut Pin<&'_ mut T>.

I personally featured this pattern with the Out references of ::uninit, and I mainly added a .r() shorthand for it:

let mut my_ptr_ty = …;
stuff(my_ptr_ty.r());
stuff(my_ptr_ty.r());

It doesn't look super pretty, which is why ppl prefer to newtype the pointee, when possible.

3 Likes

Thank you for the link! It's good to know that I am far from the only one who wants such feature. I guess for the time being I will use an explicit re-borrowing method as suggested in the other comments.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.