In the code below, how can I cast the JsValue to Foo?
#[wasm_bindgen]
pub struct Foo(u8); // Assume this can't be serialized or deserialized
#[wasm_bindgen]
pub fn foo_downcast(foo: JsValue) {
let foo: Foo = todo!();
// ...
}
From<Foo> for JsValue is implemented automatically, so I'd expect something like TryInto<Foo> for JsValue to be implemented too, but I couldn't find anything.
Vec<Foo> and &[Foo] are unsupported, but Vec<JsValue> and &[JsValue] are supported, I think)Ah yeah currently this isn't implemented. It would require an intrinsic of one form or another since the JS class lives in the JS file to test inheritance. This would be a nice feature to have though!
We've developed a workaround that discovers the runtime class name through .__proto__.constructor.name:
use wasm_bindgen::convert::FromWasmAbi;
pub fn generic_of_jsval<T: FromWasmAbi<Abi=u32>>(js: JsValue, classname: &str) -> Result<T, JsValue> {
use js_sys::{Object, Reflect};
let ctor_name = Object::get_prototype_of(&js).constructor().name();
if ctor_name == classname {
let ptr = Reflect::get(&js, &JsValue::from_str("ptr"))?;
let ptr_u32: u32 = ptr.as_f64().ok_or(JsValue::NULL)? as u32;
let foo = unsafe { T::from_abi(ptr_u32) };
Ok(foo)
} else {
Err(JsValue::NULL)
}
}
#[wasm_bindgen]
pub fn foo_of_jsval(js: JsValue) -> Option<Foo> {
generic_of_jsval(js, "Foo").unwrap_or(None)
}
Currently, "Foo" needs to be hard-coded in the snippet since the #[wasm_bindgen] derive macro doesn't generate a way to refer to it programatically. It looks like the ToTokens impl for ast::Struct (https://github.com/rustwasm/wasm-bindgen/blob/17950202ca9458d35bd78a48ebb126800edb0999/crates/backend/src/codegen.rs#L139) has a js_name that could be added. Would adding another trait to wasm_bindgen::convert that exposes this metadata and generating it from the derive macro be the preferred way to do this?
Also, should the method that performs the downcast be added to wasm_bindgen itself (possibly to the same wasm_bindgen::convert trait, if we're adding a new one), or to a different component like js_sys?
Most helpful comment
We've developed a workaround that discovers the runtime class name through
.__proto__.constructor.name:Currently,
"Foo"needs to be hard-coded in the snippet since the#[wasm_bindgen]derive macro doesn't generate a way to refer to it programatically. It looks like theToTokensimpl forast::Struct(https://github.com/rustwasm/wasm-bindgen/blob/17950202ca9458d35bd78a48ebb126800edb0999/crates/backend/src/codegen.rs#L139) has ajs_namethat could be added. Would adding another trait towasm_bindgen::convertthat exposes this metadata and generating it from the derive macro be the preferred way to do this?Also, should the method that performs the downcast be added to
wasm_bindgenitself (possibly to the samewasm_bindgen::converttrait, if we're adding a new one), or to a different component likejs_sys?