Skip to content

Commit 8f9c541

Browse files
committed
Export "C" async functions may return a Result or a normal type.
This adds a helper trait `FromJsValue`.
1 parent 13f0ba8 commit 8f9c541

File tree

2 files changed

+65
-9
lines changed

2 files changed

+65
-9
lines changed

crates/backend/src/codegen.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -973,8 +973,11 @@ impl TryToTokens for ast::ImportFunction {
973973
Some(ref ty) => {
974974
if self.function.r#async {
975975
abi_ret = quote! { js_sys::Promise };
976-
convert_ret = quote! {
977-
wasm_bindgen_futures::JsFuture::from(#ret_ident).await
976+
let future = quote! { wasm_bindgen_futures::JsFuture::from(#ret_ident).await };
977+
convert_ret = if self.catch {
978+
quote! { Ok(<#ty as wasm_bindgen::FromJsValue>::from_js_value(#future?)) }
979+
} else {
980+
quote! { <#ty as wasm_bindgen::FromJsValue>::from_js_value(#future.expect("uncaught exception")) }
978981
};
979982
} else {
980983
abi_ret = quote! {
@@ -988,18 +991,22 @@ impl TryToTokens for ast::ImportFunction {
988991
}
989992
None => {
990993
if self.function.r#async {
991-
bail_span!(
992-
self.rust_name,
993-
"an imported async function must return a Result<JsValue, JsValue>"
994-
);
994+
abi_ret = quote! { js_sys::Promise };
995+
let future = quote! { wasm_bindgen_futures::JsFuture::from(#ret_ident).await };
996+
convert_ret = if self.catch {
997+
quote! { #future?; Ok(()) }
998+
} else {
999+
quote! { #future.expect("uncaught exception"); }
1000+
};
1001+
} else {
1002+
abi_ret = quote! { () };
1003+
convert_ret = quote! { () };
9951004
}
996-
abi_ret = quote! { () };
997-
convert_ret = quote! { () };
9981005
}
9991006
}
10001007

10011008
let mut exceptional_ret = quote!();
1002-
if self.catch {
1009+
if self.catch && !self.function.r#async {
10031010
convert_ret = quote! { Ok(#convert_ret) };
10041011
exceptional_ret = quote! {
10051012
wasm_bindgen::__rt::take_last_exception()?;

src/lib.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,17 @@ macro_rules! numbers {
479479
JsValue::from_f64(n.into())
480480
}
481481
}
482+
483+
impl FromJsValue for $n {
484+
#[inline]
485+
fn from_js_value(j: JsValue) -> $n {
486+
match j.as_f64() {
487+
Some(x) => x as $n,
488+
None => $n::default()
489+
}
490+
}
491+
}
492+
482493
)*)
483494
}
484495

@@ -1172,3 +1183,41 @@ impl<T> DerefMut for Clamped<T> {
11721183
&mut self.0
11731184
}
11741185
}
1186+
1187+
/// A trait to convert a JsValue into another type.
1188+
pub trait FromJsValue {
1189+
fn from_js_value(j: JsValue) -> Self;
1190+
}
1191+
1192+
impl<T: JsCast> FromJsValue for T {
1193+
fn from_js_value(j: JsValue) -> T {
1194+
T::unchecked_from_js(j)
1195+
}
1196+
}
1197+
1198+
impl<T: FromJsValue> FromJsValue for Option<T> {
1199+
fn from_js_value(j: JsValue) -> Option<T> {
1200+
if j.is_null() || j.is_undefined() {
1201+
None
1202+
} else {
1203+
Some(T::from_js_value(j))
1204+
}
1205+
}
1206+
}
1207+
1208+
if_std! {
1209+
impl FromJsValue for String {
1210+
fn from_js_value(j: JsValue) -> String {
1211+
match j.as_string() {
1212+
Some(s) => s,
1213+
None => String::new(),
1214+
}
1215+
}
1216+
}
1217+
}
1218+
1219+
impl FromJsValue for bool {
1220+
fn from_js_value(j: JsValue) -> bool {
1221+
j.is_truthy()
1222+
}
1223+
}

0 commit comments

Comments
 (0)