Reputation: 155
I want to write function transactional
which handle logic related to transactions committing
fn get_client() -> Client {
return Client{};
}
struct Client {}
impl Client {
pub async fn commit(&mut self) -> Result<(), Error> {
return Ok(());
}
pub async fn find_and_update(&mut self) -> Vec<u64> {
return vec![];
}
}
pub async fn transactional<F, Fut, R>(action: F) -> Result<R, Error>
where
F: Fn(&mut Client) -> Fut,
Fut: Future<Output = R>
{
let mut client = get_client();
loop {
let action_result = action(&mut client).await;
if let Err(err) = client.commit().await {
continue;
}
return Ok(action_result);
}
}
pub async fn make_request() -> Vec<u64> {
return transactional(
async move |session| session.find_and_update().await
).await.unwrap();
}
#[tokio::main]
async fn main() -> Result<(), io::Error>{
let r = make_request().await;
return Ok(())
}
but i get following error
| async move |session| session.find_and_update().await
| ^^^^^^^^^^^^--------
| | | |
| | | return type of closure `impl futures::Future<Output = Vec<u64>>` contains a lifetime `'2`
| | has type `&'1 mut Client`
| returning this value requires that `'1` must outlive `'2`
is it possible to specify that &Client outlives Future and both lives less than loop iteration?
is it possible to fix this wihtout using pointers?
cargo --version
cargo 1.64.0-nightly (a5e08c470 2022-06-23)
Upvotes: 2
Views: 655
Reputation: 1697
At first I rewrote your code to not use unstable async closures. Then you see, that borrowing Client
in an async block |session| async move {..}
is only possible for 'static
and you don't have it. So you need to give it an owned value. In my case I pass ownership to the async block and return it in the result. Not sure if this is a good design, but it works.
use std::future::Future;
use tokio; // 1.19.2
fn get_client() -> Client {
return Client{};
}
pub struct Client {}
impl Client {
pub async fn commit(&mut self) -> Result<(), Error> {
return Ok(());
}
pub async fn find_and_update(&mut self) -> Vec<u64> {
return vec![];
}
}
pub async fn transactional<F, Fut, R>(action: F) -> Result<R, Error>
where
F: Fn(Client) -> Fut,
Fut: Future<Output = (R, Client)>
{
let mut client = get_client();
loop {
let (action_result, c) = action(client).await;
client = c;
if let Err(err) = client.commit().await {
continue;
}
return Ok(action_result);
}
}
pub async fn make_request() -> Vec<u64> {
return transactional(|mut session| async move { // move `client` into async, not borrow
let r = session.find_and_update().await;
(r, session)
}).await.unwrap();
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error>{
let r = make_request().await;
return Ok(())
}
#[derive(Debug)]
pub struct Error;
Upvotes: 1