dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.81k stars 84 forks source link

using async_trait in tuple generic param, error: lifetime may not live long enough #242

Open zavakid opened 1 year ago

zavakid commented 1 year ago

hi, here is the code, and will compile for (A,), but can't compile for (A, B).

here is the code in the playgoround

use async_trait::async_trait;

struct Text;

#[async_trait]
trait FromText<'r> {
    type Output;
    async fn parse(text: &'r Text) -> Self::Output;
}

// can compile for (A,)
#[async_trait]
impl<'r, A> FromText<'r> for (A,)
where
    A: FromText<'r>,
{
    type Output = (A::Output,);

    async fn parse(text: &'r Text) -> Self::Output {
        let a = A::parse(text).await;
        (a,)
    }
}

// can't compile for (A, B)
#[async_trait]
impl<'r, A, B> FromText<'r> for (A, B)
where
    A: FromText<'r>,
    B: FromText<'r>,
    A::Output: Send,
    B::Output: Send,
{
    type Output = (A::Output, B::Output);

    async fn parse(text: &'r Text) -> Self::Output {
        let a = A::parse(text).await;
        let b = B::parse(text).await;
        (a, b)
    }
}

the error message:

ompiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/lib.rs:37:52
   |
28 |   impl<'r, A, B> FromText<'r> for (A, B)
   |        -- lifetime `'r` defined here
...
37 |       async fn parse(text: &'r Text) -> Self::Output {
   |  ____________________________________________________^
38 | |         let a = A::parse(text).await;
39 | |         let b = B::parse(text).await;
40 | |         (a, b)
41 | |     }
   | |_____^ cast requires that `'r` must outlive `'static`
jackalchenxu commented 1 year ago

please use special lifetime 'async_trait, instead of 'r in declaration your trait FromText to mark out the input text is always outlive in whole parse async blocks.

here is the compilable code

zavakid commented 1 year ago

@jackalchenxu here I use 'r in the FromText because I want to impl for some reference, e.g. I can impl FromText for &str like below:

impl <'r> FromText<'r> for &str {
  type Output = &'r str;
  async fn parse(text: &'r Text) -> Self::Output  {
     // get string ref from text
  }
}

but how can I do above if I change the trait declaration?