You'll need to return a lifetime that isn't temporary for the duration of the call:
impl<'a, T> WriteGuard<'a, T> {
pub fn into_ref(self) -> &'a T { // 'a here
ManuallyDrop is generally a good direction when you want to prevent Drop, but the gotcha is that ManuallyDrop(self).entry goes through Deref that gives you a shorter lifetime (IIRC there was an RFC suggesting to give ManuallyDrop magic destructuring powers).
You'll need some unsafe to get a longer lifetime. Consult with cargo miri test for what is the right hack for preserving provenance. Maybe make WriteGuard#[repr(transparent)] and transmute it to the reference type without going through ManuallyDrop?
destructuring moves the value, currently it's not possible to directly destruct a type with drop glue. see also discussion in this thread:
except for certain very contrived special cases (you have some "dummy" values so you can do std::mem::replace(), e.g. an associated constant <T as SpecialTrait>::DUMMY), the workarounds that I know of all need unsafe.
for this particular example, where your WriteGuard has only a single field, you can mark it #[repr(transparent)] and directly transmutate it into the inner field.
for more complex cases, you can ptr::read() the field you are interested in, just remember to mem::forget() (or wrap in ManuallyDrop) the old value. other fields must be handled properly too.
Thanks for the ideas guys, I could refactor it into making the entry an Option<&'a mut T>, so I could "steal" it, and then have the Drop only do useful things if it was still a Some value.
impl<'a, T> WriteGuard<'a, T> {
pub fn commit(&mut self) {
if let Some(ref mut entry) = self.entry { ... }
}
pub fn into_ref(mut self) -> &'a T {
self.commit(); // Let's just never forget to call this though....
self.entry.take().unwrap()
}
}
impl<'a, T> Drop for WriteGuard<'a, T>
where
T: Serialize + 'static,
{
fn drop(&mut self) {
self.commit()
}
}