Skip to content

[WIP] add parameter to async function --> error #1973

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

Merged
merged 2 commits into from
Jan 22, 2020

Conversation

ultrasaurus
Copy link
Contributor

This change to the fetch example does not compile.
It would be great to include how to do this!

I got the example working locally:

cd examples/fetch
npm install
npm run serve

All is good!

Then I attempted to add a parameter to the async function, but the example fails to
compile with the following error:

$ cargo build
   Compiling fetch v0.1.0 (/Users/sallen/src/rust/wasm-bindgen/examples/fetch)
error[E0597]: `*arg0` does not live long enough
  --> examples/fetch/src/lib.rs:35:1
   |
35 | #[wasm_bindgen]
   | ^^^^^^^^^^^^^^-
   | |             |
   | |             `*arg0` dropped here while still borrowed
   | |             argument requires that `*arg0` is borrowed for `'static`
   | borrowed value does not live long enough

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `fetch`.

Perhaps I don't know the correct syntax for this.
It would be fabulous if the example illustrated how to pass a parameter.
If someone can give me a hint, I can add it :)

This change to the fetch example does not compile.
It would be great to include how to do this!
@Pauan
Copy link
Contributor

Pauan commented Jan 22, 2020

The issue is that you can't spawn a Future which is using external references, because the Future outlives the stack frame, so that would be unsound.

All Future spawners have this restriction (not just wasm-bindgen). It's complicated because this restriction only applies to references. Owned values and 'static references are completely fine.

So you have two options:

  1. You can change it to accept String instead, which doesn't contain any references so it's safe.

  2. You can instead use async move and return a Promise, like this:

#[wasm_bindgen]
pub fn run(repo: &str) -> Promise {
    let url = format!("https://api.github.com/repos/{}/branches/master", repo);

    future_to_promise(async move {
        let mut opts = RequestInit::new();
        opts.method("GET");
        opts.mode(RequestMode::Cors);

        let request = Request::new_with_str_and_init(
            &url,
            &opts,
        )?;

        request
            .headers()
            .set("Accept", "application/vnd.github.v3+json")?;

        let window = web_sys::window().unwrap();
        let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;

        // `resp_value` is a `Response` object.
        assert!(resp_value.is_instance_of::<Response>());
        let resp: Response = resp_value.dyn_into().unwrap();

        // Convert this other `Promise` into a rust `Future`.
        let json = JsFuture::from(resp.json()?).await?;

        // Use serde to parse the JSON into a struct.
        let branch_info: Branch = json.into_serde().unwrap();

        // Send the `Branch` struct back to JS as an `Object`.
        Ok(JsValue::from_serde(&branch_info).unwrap())
    })
}

This works because it's converting the &str into a String outside of the async move, and then using the String inside of the async move. So there's no references, so everything's okay.

@ultrasaurus
Copy link
Contributor Author

What a great explanation. Thank you @Pauan !

The problem was obvious once you pointed it out, but it was so helpful to see the solution, since it can be sometimes hard to construct the correct Rust syntax.

In any case, I've updated the PR using String for the param, since that seems like a simpler approach for this example.

@alexcrichton alexcrichton merged commit ae6f4a9 into rustwasm:master Jan 22, 2020
@alexcrichton
Copy link
Contributor

Looks great to me, thanks!

@shijunti19
Copy link

@alexcrichton Reference problem: I can't add a loading state before the request, assign true to the request to prevent concurrency, and assign false after the request

@alexcrichton
Copy link
Contributor

Hm I'm not sure I quite understand @shijunti19, can you file a separate issue?

@shijunti19
Copy link

@alexcrichton #2354

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

Successfully merging this pull request may close these issues.

4 participants