-1

I try to create a transaction object from a parent connection being in async context. Here is a distilled situation:

use std::fmt::Debug;
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::result::Result as StdResult;

#[derive(Debug)]
enum Error {
    Unknown,
}

type Result<T> = StdResult<T, Error>;

type Future<'a, T> = Pin<Box<dyn StdFuture<Output = T> + Send + 'a>>;

trait DataConn<'c> {
    type Tx: DataTx<'c>;

    fn begin(&'c mut self) -> Future<Result<Self::Tx>>;
}

trait DataTx<'c> {
    type Tx: DataTx<'c>;

    fn begin(&'c mut self) -> Future<Result<Self::Tx>>;
}

async fn test_transactions<'c>(mut conn: impl DataConn<'c> + 'c)
{
    let tx = conn.begin().await.unwrap();
}

As result I get the following error:

error[E0597]: `conn` does not live long enough
  --> src/lib.rs:29:14
   |
27 | async fn test_transactions<'c>(mut conn: impl DataConn<'c> + 'c)
   |                            -- lifetime `'c` defined here
28 | {
29 |     let tx = conn.begin().await.unwrap();
   |              ^^^^^^^^^^^^
   |              |
   |              borrowed value does not live long enough
   |              argument requires that `conn` is borrowed for `'c`
30 | }
   | - `conn` dropped here while still borrowed

I don't get why the connection is going to be dropped before the transaction we create, while both have the same 'c lifetime. What do I miss here?

UPDATE: Some suggestions work being standalone, but cause compilation errors for my trait implementation:

struct SqliteConn<'c> {
    conn: sqlx::SqliteConnection,
    phantom: PhantomData<&'c ()>,
}

pub struct SqliteTx<'c> {
    tx: Transaction<'c, Sqlite>,
}

impl<'c> DataConn<'c> for SqliteConn<'c> {
    type Tx = SqliteTx<'c>;

    fn begin(&'c mut self) -> Future<Result<Self::Tx>> {
        Box::pin(async move {
            Ok(SqliteTx {
                tx: Connection::begin(&mut self.conn).await?,
            })
        })
    }
}
ababo
  • 1,490
  • 1
  • 10
  • 24
  • Do you need those lifetime annotations? Not sure about your design requirements, but [your code compiles with all the `'c`'s removed](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b9c44511fbc9c78e7b2283231cfb0a92). Also, returning `DataTx` from those trait methods is likely not going to work. – kotatsuyaki May 29 '22 at 07:51
  • The problem is that then I fail to implement the trait. In fact `DataConn` implementation incapsulates `sqlx::SqliteConnection`. – ababo May 29 '22 at 08:11

1 Answers1

0

You just need to annotate whatever necessary, just over the transaction lifetime (don't mess with self lifetimes here):

use std::fmt::Debug;
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::result::Result as StdResult;

#[derive(Debug)]
enum Error {
    Unknown,
}

type Result<T> = StdResult<T, Error>;

type Future<'a, T> = Pin<Box<dyn StdFuture<Output = T> + Send + 'a>>;

trait DataConn<'t> {
    type Tx: DataTx<'t>;

    fn begin(&mut self) -> Future<Result<Self::Tx>>;
}

trait DataTx<'t> {
    type Tx: DataTx<'t>;

    fn begin(&self) -> Future<Result<Self::Tx>>;
}

async fn test_transactions<'t>(mut conn: impl DataConn<'t>)
{
    let tx = conn.begin().await.unwrap();
}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • Please take a look for the post update, your change breaks my code. – ababo May 29 '22 at 08:24
  • 2
    @ababo, this is what happens when there is not enough information to reproduce the problem. You shouldn't edit questions to add more problems, but open newly related ones. – Netwave May 29 '22 at 08:28
  • But this is the same problem. You see this trait form just because of the implementation constraints. – ababo May 29 '22 at 08:29
  • @Netwave (Haven't read, neither the original nor the updated post, however) If you think an edit changed the question in a post, roll it back or if you aren't sure/don't want to open a question at Meta. Don't let violations happen, especially when they harm answers. – Chayim Friedman May 29 '22 at 16:07
  • 2
    @ChayimFriedman definitely. But also ideally it should be the responsibility of the one making the question. Sadly usually just want quick answers to their problem without thinking that this is for everyone beyond that too. – Netwave May 29 '22 at 16:17