Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow async traits #2409

Closed
ineiti opened this issue Dec 31, 2020 · 4 comments
Closed

Allow async traits #2409

ineiti opened this issue Dec 31, 2020 · 4 comments

Comments

@ineiti
Copy link

ineiti commented Dec 31, 2020

Motivation

I would like to use traits to write common code that can be used for wasm and i586 binaries. Part of the code should interact with the network. So I'd like to define a network trait that can be implemented for the wasm part and the i586 part.

Proposed Solution

A simple use-case would be the following:

use wasm_bindgen::prelude::*;

use async_trait::async_trait;

#[wasm_bindgen(inline_js = "export function wait_ms(ms) { return new Promise((r) => setTimeout(r, ms)); }")]
extern "C" {
    pub async fn wait_ms(ms: u32);
}

#[wasm_bindgen]
pub async fn start() -> Result<(), JsValue> {
    let ai = AsyncImpl {};
    ai.something("").await?;
    Ok(())
}

#[async_trait]
trait AsyncTrait {
    async fn something(&self, s: &str) -> Result<String, String>;
}

struct AsyncImpl {}

#[async_trait]
impl AsyncTrait for AsyncImpl {
    async fn something(&self, s: &str) -> Result<String, String> {
        wait_ms(1000).await;
        Ok("".to_string())
    }
}

Alternatives

I tried to come up with alternatives that don't include the async-trait, but couldn't make it work. Any proposition is welcome ;)

Additional Context

It should be possible to implement the trait for rest-requests and webrtc requests. The above code complains with

error: future cannot be sent between threads safely
[...]
   = help: within `impl futures::Future`, the trait `std::marker::Send` is not implemented for `Rc<RefCell<wasm_bindgen_futures::Inner>>`
note: future is not `Send` as it awaits another future which is not `Send`
@alexcrichton
Copy link
Contributor

Thanks for the report! I believe the issue here is the Send/Sync bounds automatically added with async_trait. You'll want to opt-out of those. Otherwise I think this should work!

@ineiti
Copy link
Author

ineiti commented Jan 5, 2021

It's magic! Using

#[async_trait(?Send)]

on both the trait and the implementation makes this work! Of course, RTFM would have helped here...

https://github.com/dtolnay/async-trait/blame/master/README.md#L134

Thanks a lot! Up to new adventures I go.

@ctaggart
Copy link
Contributor

I'm trying to make the HttpClient compile to wasm in Azure/azure-sdk-for-rust#228. Changing it to #[async_trait(?Send)] did allow it to compile to wasm, but resulted in a cascade of changes. Also, @rylev says:

I believe we want futures which can be sent across thread boundaries. If we're using tokio for instance, you want to be able to to use a multi-threaded runtime.

@alexcrichton, could you please elaborate on why:

I believe the issue here is the Send/Sync bounds automatically added with async_trait. You'll want to opt-out of those.

I have a hunch, but just seeing if there is a fundamental incompatibility. Thank you.

@alexcrichton
Copy link
Contributor

Futures generated with wasm-bindgen aren't Send so if you use async traits with wasm-bindgen you'll have to turn that off. Otherwise you'll need to arrange yourself for futures to be send by spawning tasks and such and using channels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants