I have a Parent
which contains an Option<Child>
and each Child
contains a Target
.
struct MyError {}
struct Target {}
struct Child {
target: Target,
}
struct Parent {
child: Option<Child>,
}
Creating a Parent
or Child
can fail:
impl Child {
fn allocate_self() -> Result<Self, MyError> {
Ok(Self { target: Target {} }) // could fail
}
}
impl Parent {
fn allocate_self() -> Result<Self, MyError> {
Ok(Self { child: None }) // could fail
}
}
My goal is to:
- Allocate the
Parent
, returning an error on failure. - Allocate the
Child
, returning an error on failure as well as freeing theParent
. - Return the
&mut Target
on success.
So far I have:
impl Child {
fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
if this_opt.is_none() {
*this_opt = Some(Self::allocate_self()?);
}
Ok(&mut this_opt.as_mut().unwrap().target)
}
}
impl Parent {
fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
if this_opt.is_none() {
*this_opt = Some(Self::allocate_self()?)
}
let this = this_opt.as_mut().unwrap();
let result = Child::retrieve_target(&mut this.child);
// GOAL: if Child::retrieve_target succeeds,
// return the result, otherwise turn ourselves back into a None
if result.is_err() {
drop(this_opt.take());
}
result
}
}
The problem is that Parent::retrieve_target
fails with a compiler error:
error[E0499]: cannot borrow `*this_opt` as mutable more than once at a time
--> src/lib.rs:44:18
|
35 | fn retrieve_target(this_opt: &mut Option<Self>) -> Result<&mut Target, MyError> {
| - let's call the lifetime of this reference `'1`
...
39 | let this = this_opt.as_mut().unwrap();
| -------- first mutable borrow occurs here
...
44 | drop(this_opt.take());
| ^^^^^^^^ second mutable borrow occurs here
45 | }
46 | result
| ------ returning this value requires that `*this_opt` is borrowed for `'1`
I've tried an assortment of methods to try to tell the compiler that the Err
part of the Result
doesn't borrow this_opt
but without success.
One solution is to first perform the allocations and then retrieve the target. However, in my use case, I have multiple layers (4 layer page table) and so ideally I'd be able to return the Target
once I get to it. Since each layer has to do roughly the same thing, I'd like it to be possible that a macro with some simple name substitutions would be able to create a multi-layered structure.
Is this possible to write (ideally safely and concisely) and if so how?