Here's a complete playground example of the code.
I have a struct that encodes values into an owned buffer. It uses the bumpalo crate's Bump and Vec<'a, T> types, locally aliasing them Bump -> BumpAllocator and Vec -> BumpVec.
struct ValueWriter<'value> {
// We have this reference to enable the creation of more buffers,
// out of scope for this problem but part of the data structure.
allocator: &'value BumpAllocator,
// Our Vec only contains unsigned bytes
buffer: &'value mut BumpVec<'value, u8>
}
I would like write an accessor method that lends out a &mut reference to the buffer field, but which lends it out with a lifetime that is shorter than 'value.
If I write a method like this:
fn buffer(&'value mut self) -> &'value BumpVec<'value> {
self.buffer
}
then any caller would tie up the ValueWriter for the entirety of 'value; I can't do anything else to self.
let mut writer = ValueWriter::new(...);
let l = writer.buffer().len(); // contrived example
writer.do_stuff(); // ERROR; `writer` cannot be borrowed a second time
If I could instead write a method with this signature:
pub fn buffer(&mut self) -> &'_ mut BumpVec<'_, u8> {
todo!()
}
...I'd be able to access the buffer as needed in the parent scope without locking up self.
Having stubbed my toe on a series of errors discussing invariance, I took the time to try and better understand the reference's chapter on Subtyping and Variance, which gives this example:
I think that it's saying that &mut T cannot do lifetime subtyping because it would be possible to assign a short-lived value to a field in the longer-lived struct, which would lead to undefined behavior when you went back to working with the longer-lived struct.
What I'm unclear on is whether my unsafe code is hazardous given that my struct's only mutable field is a BumpVec<'value, u8>, which only stores values that are Copy/'static (u8). It seems like in this case it might be alright; I'm able to implement the method above with unsafe casting and it's working (for now!) but I'd like the opinion of someone with a stronger grasp of variance and UB.
Thanks for any help!
EDIT: I should clarify: I know that it's possible to achieve the above safely if I modify ValueWriter to use multiple lifetimes. However, the type is very central to my API and is used in GATs which currently introduces several sharp edges I'm looking to sidestep. If my unsafe approach is dangerous, I'd like to understand why.
