Make `RefCell` support slice splitting?


#1

Right now, RefCell supports a single RefMut to exist a time. That RefMut can be converted using a map method from a RefMut<T> to a RefMut<U>. However, slices can be split using the split_at or split_at_mut methods. There is no equivalent way to split a RefMut.

Proposal: Make RefCell track a mutable count as well as an immutable count. The RefCell would be considered mutably borrowed if the mutable count was nonzero. RefMut could then provide a split method with a signature like fn split<U, F: Fn(&mut T) -> (&mut U, &mut U)>(self, f: F) -> (RefMut<U>, RefMut<U>), and would thus provide the RefCell analog of splitting slices or other referenced objects.


#2

I suspect we can even do this without a breaking change. RefCell keeps track of the number of references with a usize, where !0 is a sentinel value for “mutable refence taken”. We could conceivably replace with with an isize and break no clients (because, afaik, there is no way you can fill half of the address space with Ref or RefMut pointers), where now self.borrow < 0 indicates mutable references have been taken.

I’m somewhat concerned that there is some subtlety about UnsafeCell that’s been swept under the rug, but several minutes of thinking have been unable to produce pathological examples to show this is unsound.


#3

Yep, that was roughly what I was thinking.

I’m pretty sure it’s sound because it’s almost exactly the same logic as is currently used for Ref. But it will definitely require more thought.


#4

OK, here’s a PR: https://github.com/rust-lang/rust/pull/51466