I'm implementing a buffer with copy-on-write semantics and was running into some issues with the borrow checker when implementing a make_mut() method.
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq)]
struct CowBuffer<T> {
elements: Arc<[T]>,
}
impl<T: Clone> CowBuffer<T> {
pub fn make_mut(&mut self) -> &mut [T] {
// Note: we can't use Arc::make_mut() because [T] is not Clone
if let Some(elements) = Arc::get_mut(&mut self.elements) {
return elements;
}
// Looks like more than one person has access to our elements
// so we need to make a copy.
self.elements = self.elements.iter().cloned().collect();
Arc::get_mut(&mut self.elements).expect("Guaranteed to be unique")
}
}
And the compile error:
error[E0506]: cannot assign to `self.elements` because it is borrowed
--> src/lib.rs:18:9
|
9 | pub fn make_mut(&mut self) -> &mut [T] {
| - let's call the lifetime of this reference `'1`
...
12 | if let Some(elements) = Arc::get_mut(&mut self.elements) {
| ------------------ borrow of `self.elements` occurs here
13 | return elements;
| -------- returning this value requires that `self.elements` is borrowed for `'1`
...
18 | self.elements = self.elements.iter().cloned().collect();
| ^^^^^^^^^^^^^ assignment to borrowed `self.elements` occurs here
I understand why the error occurs - the borrow in that first Arc::get_mut() call is similar to mutating self-referential types in that we "lock" self for the duration of the method call. That means any further uses (like re-assigning self.elements later on) will fail because self is already mutably borrowed.
My question is whether there are any workarounds I can use without changing the method signature?
I could always switch to a with_mut() method that takes a FnMut(&mut [T]) closure, but that isn't quite as ergonomic.