Hi, I am trying to write trait that takes a closure as argument to modify a value and get it back.
I am on nightly and using generic_associated_types
and type_alias_impl_trait
features.
Here is the code in question
pub trait EditRegister<R, A, E>
where
for<'a> R: EditableRegister<Address = A, Error = E> + 'a,
{
/// The return type of the write
type Output<'a>: Future<Output = Result<(), E>>
where
Self: 'a;
/// Edit a register. The closure takes a reference to the register,
/// the same register must be edited, then returned.
fn edit<'a, 'w, F>(&'a mut self, f: F) -> Self::Output<'a>
where
F: FnOnce(&'w mut R) -> &'w R + 'a;
}
/// Implementation of the edit register
impl<I, R, A, E> EditRegister<R, A, E> for I
where
for<'a> R: EditableRegister<Address = A, Error = E> + 'a,
I: RegisterInterface<R, A, E>, // Provide the read and write register functions
for<'a> A: 'a,
for<'a> E: 'a,
{
type Output<'a> = impl Future<Output = Result<(), E>> +'a where Self: 'a;
fn edit<'a: 'w, 'w, F>(&'a mut self, f: F) -> Self::Output<'a>
where
F: FnOnce(&'w mut R) -> &'w R + 'a,
{
async {
let mut val = self.read_register().await?;
let res = f(&mut val);
self.write_register(res).await
}
}
}
Here is the output of the compilation
❯ cargo build
Compiling device-register-async v0.1.0
error[E0597]: `val` does not live long enough
--> device-register-async/src/lib.rs:123:25
|
117 | fn edit<'a: 'w, 'w, F>(&'a mut self, f: F) -> Self::Output<'a>
| -- lifetime `'w` defined here
...
123 | let res = f(&mut val);
| --^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `val` is borrowed for `'w`
124 | self.write_register(res).await
125 | }
| - `val` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
error: could not compile `device-register-async` due to previous error
How come val is dropped while still borrowed? Shouldn't the closure only borrow it for the lifetime 'w, which should be shorter than 'a? Now I guess is that since it's a future, the closure can be evaluated later, but the lifetime 'a is already given to it. Is there any workaround to make sure that val is not dropped? Or maybe I need to pin the closure?
Any help is appreciated