Skip to content

Commit

Permalink
Adding in async support for start (#1905)
Browse files Browse the repository at this point in the history
* Adding in async support for start

* Adding in another test case

* Refactoring the Start trait to be cleaner
  • Loading branch information
Pauan authored and alexcrichton committed Dec 9, 2019
1 parent b71b136 commit 1c08e2b
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 6 deletions.
32 changes: 26 additions & 6 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,17 +447,37 @@ impl TryToTokens for ast::Export {
// since we're returning a promise to JS, and this will implicitly
// require that the function returns a `Future<Output = Result<...>>`
let (ret_ty, ret_expr) = if self.function.r#async {
if self.start {
(
quote! { () },
quote! {
wasm_bindgen_futures::spawn_local(async move {
<#syn_ret as wasm_bindgen::__rt::Start>::start(#ret.await);
})
},
)

} else {
(
quote! { wasm_bindgen::JsValue },
quote! {
wasm_bindgen_futures::future_to_promise(async move {
<#syn_ret as wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
}).into()
},
)
}

} else if self.start {
(
quote! { wasm_bindgen::JsValue },
quote! {
wasm_bindgen_futures::future_to_promise(async {
wasm_bindgen::__rt::IntoJsResult::into_js_result(#ret.await)
}).into()
},
quote! { () },
quote! { <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret) },
)

} else {
(quote! { #syn_ret }, quote! { #ret })
};

let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> };
let convert_ret = quote! { #projection::return_abi(#ret_expr) };
let describe_ret = quote! {
Expand Down
21 changes: 21 additions & 0 deletions crates/macro/ui-tests/start-function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,25 @@ pub fn foo2(x: u32) {}
#[wasm_bindgen(start)]
pub fn foo3<T>() {}

#[wasm_bindgen(start)]
pub fn foo4() -> Result<(), JsValue> { Ok(()) }

#[wasm_bindgen(start)]
pub fn foo5() -> Result<JsValue, ()> { Err(()) }

#[wasm_bindgen(start)]
pub fn foo6() -> Result<JsValue, JsValue> { Ok(JsValue::from(1u32)) }

#[wasm_bindgen(start)]
pub async fn foo_async1() {}

#[wasm_bindgen(start)]
pub async fn foo_async2() -> Result<(), JsValue> { Ok(()) }

#[wasm_bindgen(start)]
pub async fn foo_async3() -> Result<JsValue, ()> { Err(()) }

#[wasm_bindgen(start)]
pub async fn foo_async4() -> Result<JsValue, JsValue> { Ok(JsValue::from(1u32)) }

fn main() {}
20 changes: 20 additions & 0 deletions crates/macro/ui-tests/start-function.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,23 @@ error: the start function cannot have generics
|
10 | pub fn foo3<T>() {}
| ^^^

error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, ()>: wasm_bindgen::__rt::Start` is not satisfied
--> $DIR/start-function.rs:27:1
|
27 | #[wasm_bindgen(start)]
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::Start` is not implemented for `std::result::Result<wasm_bindgen::JsValue, ()>`
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`

error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: wasm_bindgen::__rt::Start` is not satisfied
--> $DIR/start-function.rs:30:1
|
30 | #[wasm_bindgen(start)]
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `wasm_bindgen::__rt::Start` is not implemented for `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
|
= help: the following implementations were found:
<std::result::Result<(), E> as wasm_bindgen::__rt::Start>
= note: required by `wasm_bindgen::__rt::Start::start`
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,27 @@ pub mod __rt {
}
}
}


/// An internal helper trait for usage in `#[wasm_bindgen(start)]`
/// functions to throw the error (if it is `Err`).
pub trait Start {
fn start(self);
}

impl Start for () {
#[inline]
fn start(self) {}
}

impl<E: Into<JsValue>> Start for Result<(), E> {
#[inline]
fn start(self) {
if let Err(e) = self {
crate::throw_val(e.into());
}
}
}
}

/// A wrapper type around slices and vectors for binding the `Uint8ClampedArray`
Expand Down

0 comments on commit 1c08e2b

Please sign in to comment.