The trait `Send` is not implemented when using async-trait crate

I'm trying to create an async trait using the async-trait crate. I want the trait A to be implemented by B and I want B to house another of it's kind. A dyn type also implementing the A trait.

Minimal example with A also taking a generic type T because in my real example it does that for other reasons, but including it here in case it influences the solution.

#[async_trait]
trait A<T = ()> {
    async fn foo(&mut self) -> u8;
}

struct B<T> {
    a: Box<dyn A<T>>,
}
impl<T: Send + Unpin> A<T> for B<T> {
    fn foo<'a, 'b>(& 'a mut self) -> Pin<Box<dyn Future<Output = u8> + Send + 'b>> where 'a: 'b, Self: 'b {
        async fn run<T: Send + Unpin>(_self: &mut B<T>) -> u8 {
            let a = _self.a.foo();
            let a = a.await;
            return a;
        }

        Box::pin(run(self)) // future returned by `run` is not `Send`
    }
}

Here is the link to the example in the playground

I'm guessing B has to impl Send which means all of it's members also must impl Send?

Yes. You need to change struct B. (If you need the Send bound on trait.)

struct B<T> {
    a: Box<dyn A<T> + Send>,
}
1 Like

If you don't want to add + Send on every dyn A, then there is another possibility:

#[async_trait]
trait A<T = ()>: Send {
    async fn foo(&mut self) -> u8;
}
4 Likes

Another option is to remove the Send requirement:

-#[async_trait]
+#[async_trait(?Send)]
 trait A<T = ()> {
     async fn foo(&mut self) -> u8;
 }
 
 struct B<T> {
     a: Box<dyn A<T>>,
 }
 impl<T: Send + Unpin> A<T> for B<T> {
-    fn foo<'a, 'b>(& 'a mut self) -> Pin<Box<dyn Future<Output = u8> + Send + 'b>> where 'a: 'b, Self: 'b {
+    fn foo<'a, 'b>(& 'a mut self) -> Pin<Box<dyn Future<Output = u8> + 'b>> where 'a: 'b, Self: 'b {
         async fn run<T: Send + Unpin>(_self: &mut B<T>) -> u8 {
             let a = _self.a.foo();
             let a = a.await;
             return a;
         }
 
         Box::pin(run(self))
     }
 }

(Playground)

However, that would mean you cannot rely on the future returned by A::foo to be Send. This makes it impossible to move Futures to other threads. So this solution is normally not what you would want to do. But I wanted to mention it nonetheless.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.