mwlon
mwlon

Reputation: 1006

How to use rust async_trait generic to a lifetime parameter?

I'm trying to make an async_trait where some implementations are generic to types with lifetime parameters:

use async_trait::async_trait;

struct MyLifetimeType<'a> {
  s: &'a mut String,
}

#[async_trait]
trait MyTrait<T> {
  async fn handle(t: T);
}

struct MyImpl;

#[async_trait]
impl<'a> MyTrait<MyLifetimeType<'a>> for MyImpl {
  async fn handle(t: MyLifetimeType<'a>) {
    t.s.push_str("hi");
  }
}

When I try to compile this, I get

error[E0276]: impl has stricter requirements than trait
  --> ...
   |
18 |   async fn handle(t: T);
   |   ---------------------- definition of `handle` from trait
...
25 |   async fn handle(t: MyLifetimeType<'a>) {
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'async_trait`

It seems that the issue is related to async_trait somehow using the lifetime parameter 'a under the hood. When I get rid of all the async and async_trait, the code compiles fine. How can I avoid this extra requirement error?

For more context, to explain why have handlers implementing MyTrait that can operate on structs containing mutable pointers: I have a function that obtains RwLockReadGuards and RwLockWriteGuards for a couple different locks, then passes the contents to a handler. For the write guards, I need some way for the handler to mutate contents, so I pass a mutable pointer.

Upvotes: 1

Views: 2447

Answers (1)

Svetlin Zarev
Svetlin Zarev

Reputation: 15673

This is a known issue. The author recommends adding an explicit lifetime bound when that error occurs:

use async_trait::async_trait;

struct MyLifetimeType<'a> {
  s: &'a mut String,
}

#[async_trait]
trait MyTrait<T> {
  async fn handle(&self, t: T) where T: 'async_trait;
}

struct MyImpl;

#[async_trait]
impl<'a> MyTrait<MyLifetimeType<'a>> for MyImpl {

  async fn handle(&self, t: MyLifetimeType<'a>) {
    t.s.push_str("hi");
  }
  
}

Upvotes: 4

Related Questions