I cannot understand how to fix the below code: Rust Explorer Playground: Rust Explorer.
How can I fix that lifetime?
/*
[dependencies]
async-trait = "0.1.61"
sqlx = { version = "0.6.2", default-features = false, features = [
"macros",
"postgres",
"runtime-tokio-native-tls",
"time",
] }
tokio = { version = "1.24.1", features = ["full"] }
*/
use std::{future::Future, pin::Pin, sync::Arc};
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
#[async_trait::async_trait]
pub trait Player: Send + Sync {
async fn player_create<'a>(
&'a self,
team_id: &str,
_input: &PlayerInput,
lambda: &(dyn for<'b> Fn(
PlayerCreateLambdaArgs<'b>,
)
-> Pin<Box<dyn Future<Output = Result<DomainPlayer, String>> + Send + 'b>>
+ Sync
+ '_),
) -> Result<DomainPlayer, String>;
}
#[async_trait::async_trait]
pub trait Shirt: Send + Sync {
async fn shirt_get_next_and_increase(
&self,
tx: &mut sqlx::PgConnection,
model: String,
) -> Result<i64, String>;
}
pub struct Repo {
pub pool: Arc<sqlx::PgPool>,
}
impl Repo {
pub fn new(pool: Arc<sqlx::PgPool>) -> Self {
Self { pool }
}
}
#[async_trait::async_trait]
impl Player for Repo {
async fn player_create(
&self,
_team_id: &str,
_input: &PlayerInput,
lambda: &(dyn for<'b> Fn(
PlayerCreateLambdaArgs<'b>,
)
-> Pin<Box<dyn Future<Output = Result<DomainPlayer, String>> + Send + 'b>>
+ Sync
+ '_),
) -> Result<DomainPlayer, String> {
let mut tx = self.pool.begin().await.unwrap();
// use _input here
let domain_player = lambda(PlayerCreateLambdaArgs {
shirt_next_value: Box::new(|model: String| {
self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
}),
})
.await?;
let res =
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
.fetch_one(&mut *tx)
.await
.unwrap();
Ok(res)
}
}
#[async_trait::async_trait]
impl Shirt for Repo {
async fn shirt_get_next_and_increase(
&self,
_tx: &mut sqlx::PgConnection,
_model: String,
) -> Result<i64, String> {
// Here I'm awaiting an async call for DB operations using the same DB transacion of the caller (_tx)...
// use _tx here...
let res = 123;
Ok(res)
}
}
pub struct Needs {
pub command_pg_repo: Arc<dyn Trait>,
}
#[derive(Default)]
pub struct PlayerInput {
pub id: String,
}
#[derive(Debug, Default, Clone, sqlx::FromRow)]
pub struct DomainPlayer {
pub id: String,
pub shirt_number: i64,
}
pub struct PlayerCreateLambdaArgs<'a> {
// other needed fields here
pub shirt_next_value: Box<
dyn FnOnce(String) -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send + 'a>>
+ Send
+ Sync
+ 'a,
>,
}
pub struct Handler {
needs: Arc<Needs>,
}
impl Handler {
pub fn new(needs: Arc<Needs>) -> Self {
Self { needs }
}
pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
let res = self
.needs
.command_pg_repo
.player_create("team", &input, &|args| {
let input = input;
Box::pin(async move {
let shirt_number = (args.shirt_next_value)("player".to_string()).await?;
let o = DomainPlayer {
id: input.id,
shirt_number,
};
Ok(o)
})
})
.await?;
Ok(res)
}
}
#[tokio::main]
async fn main() -> Result<(), String> {
let db_conn = sqlx::PgPool::connect("fake_url").await.unwrap();
let pg_repo = Arc::new(Repo::new(Arc::new(db_conn)));
let needs = Arc::new(Needs {
command_pg_repo: pg_repo,
});
let handler = Handler::new(needs);
let new_player_input = PlayerInput {
id: "abc".to_string(),
};
let player = handler.handle(&new_player_input).await?;
dbg!(player);
Ok(())
}
The error:
error[E0507]: cannot move out of `input.id` which is behind a shared reference
--> src/main.rs:151:29
|
151 | id: input.id,
| ^^^^^^^^ move occurs because `input.id` has type `std::string::String`, which does not implement the `Copy` trait
error: lifetime may not live long enough
--> src/main.rs:147:17
|
140 | pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
| - let's call the lifetime of this reference `'1`
...
147 | / Box::pin(async move {
148 | | let shirt_number = (args.shirt_next_value)("player".to_string()).await?;
149 | |
150 | | let o = DomainPlayer {
... |
155 | | Ok(o)
156 | | })
| |__________________^ returning this value requires that `'1` must outlive `'static`
For more information about this error, try `rustc --explain E0507`.