Skip to content

Split Promise<primitive> into raw extern + async wrapper#11

Closed
connyay wants to merge 1 commit into
wasm-bindgen:mainfrom
connyay:primitive-async-wrapper
Closed

Split Promise<primitive> into raw extern + async wrapper#11
connyay wants to merge 1 commit into
wasm-bindgen:mainfrom
connyay:primitive-async-wrapper

Conversation

@connyay

@connyay connyay commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Methods returning Promise<boolean | string | number> now emit a synchronous Promise-returning extern plus an inherent-impl async fn that awaits and casts the resolved JsValue. The public signature (pub async fn -> Result<T, JsValue>) is unchanged.

Why: some wasm-bindgen flavours (notably the workers-rs fork) tightened Promise / JsFuture to require T: JsGeneric, which Rust primitives don't impl, so a direct
pub async fn -> Result<bool, JsValue> extern fails to compile under those flavours. Routing through js_sys::Promise (no JsGeneric bound) avoids the constraint, and the JsValue::as_* cast happens once in the wrapper instead of at every call site. Custom @throws error types still go through the existing
From for CustomError contract via a trailing .into().

Methods returning Promise<boolean | string | number> now emit a
synchronous Promise-returning extern plus an inherent-impl async fn
that awaits and casts the resolved JsValue. The public signature
(pub async fn -> Result<T, JsValue>) is unchanged.

Why: some wasm-bindgen flavours (notably the workers-rs fork)
tightened Promise<T> / JsFuture<T> to require T: JsGeneric, which
Rust primitives don't impl, so a direct
`pub async fn -> Result<bool, JsValue>` extern fails to compile
under those flavours. Routing through js_sys::Promise (no JsGeneric
bound) avoids the constraint, and the JsValue::as_* cast happens
once in the wrapper instead of at every call site. Custom @throws
error types still go through the existing
From<JsValue> for CustomError contract via a trailing .into().
@guybedford

Copy link
Copy Markdown
Contributor

This is the unfortunate aspect of using erasable generics - JsGeneric must be an externref in Wasm, so it cannot be a Rust primitive at all. So instead we use Number, JsString, Boolean JS primitive type wrappers instead, which are still effectively externref variants.

So rather I think the fix we need here is the conversion of the type to the canonical JS type instead of the Rust primitive on the async generics.

@connyay

connyay commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

closing in favor of #14

@connyay connyay closed this Apr 29, 2026
@connyay connyay deleted the primitive-async-wrapper branch April 29, 2026 22:27
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.

2 participants