Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Future is not Send, only when from async Trait

I have a trait Serializer:

trait Serializer {
    fn serialize(&self, data: Rc<()>) -> Result<(), Error>;
}

And some Foo which implements it. Notably, data is not Send.

The actual implementation requires an async context to execute, so I’ve split the creation of an async runtime away from the actual implementation, like so:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct Foo {}

impl Foo {
    async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
        unimplemented!();
    }
}

impl Serializer for Foo {
    fn serialize(&self, data: Rc<()>) -> Result<(), Error> {
        let runtime = Builder::new_current_thread().enable_all().build().unwrap();
        runtime.block_on(async move { self.async_serialize(data).await })
    }
}

This compiles and works how I would expect.

If I refactor the code such that the async Runtime creation is done by way of a trait:

#[async_trait]
trait AsyncSerializer {
    async fn async_serialize(&self, data: Rc<()>) -> Result<(), Error>;
}

#[async_trait]
impl AsyncSerializer for Foo {
    async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
        unimplemented!();
    }
}

This does not compile, now complaining that Rc<()> isn’t Send:

error: future cannot be sent between threads safely
  --> src/main.rs:19:73
   |
19 |       async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
   |  _________________________________________________________________________^
20 | |         unimplemented!();
21 | |     }
   | |_____^ future created by async block is not `Send`
   |
   = help: within `impl Future<Output = Result<(), anyhow::Error>>`, the trait `Send` is not implemented for `Rc<()>`
note: captured value is not `Send`

This error message makes sense to me, Rc is not Send, but:

  • Why was this not a problem before? The prior implementations (impl on Foo versus impl AsyncSerializer for Foo) look analogous to me.
  • Can I wrap data in some way to avoid this?

>Solution :

The way that #[async_trait] de-sugars your code requires your futures to be send, as explained here. To fix that change the attribute macro to be #[async_trait(?Send)].

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading