mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-07-31 03:51:56 +00:00
Implement JsCast
for all imported types
This commit implements the `JsCast` trait automatically for all imported types in `#[wasm_bindgen] extern { ... }` blocks. The main change here was to generate an `instanceof` shim for all imported types in case it's needed. All imported types now also implement `AsRef<JsValue>` and `AsMut<JsValue>`
This commit is contained in:
@@ -127,6 +127,7 @@ pub struct ImportType {
|
||||
pub name: Ident,
|
||||
pub attrs: Vec<syn::Attribute>,
|
||||
pub doc_comment: Option<String>,
|
||||
pub instanceof_shim: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
@@ -408,7 +409,10 @@ impl ImportStatic {
|
||||
|
||||
impl ImportType {
|
||||
fn shared(&self) -> shared::ImportType {
|
||||
shared::ImportType {}
|
||||
shared::ImportType {
|
||||
name: self.name.to_string(),
|
||||
instanceof_shim: self.instanceof_shim.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -521,10 +521,12 @@ impl ToTokens for ast::ImportType {
|
||||
};
|
||||
let const_name = format!("__wbg_generated_const_{}", name);
|
||||
let const_name = Ident::new(&const_name, Span::call_site());
|
||||
let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
|
||||
(quote! {
|
||||
#[allow(bad_style)]
|
||||
#(#attrs)*
|
||||
#[doc = #doc_comment]
|
||||
#[repr(transparent)]
|
||||
#vis struct #name {
|
||||
obj: ::wasm_bindgen::JsValue,
|
||||
}
|
||||
@@ -533,7 +535,7 @@ impl ToTokens for ast::ImportType {
|
||||
const #const_name: () = {
|
||||
use wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi, Stack};
|
||||
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
|
||||
use wasm_bindgen::convert::RefFromWasmAbi;
|
||||
use wasm_bindgen::convert::{RefFromWasmAbi, GlobalStack};
|
||||
use wasm_bindgen::describe::WasmDescribe;
|
||||
use wasm_bindgen::{JsValue, JsCast};
|
||||
use wasm_bindgen::__rt::core::mem::ManuallyDrop;
|
||||
@@ -594,18 +596,63 @@ impl ToTokens for ast::ImportType {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this on the next major version
|
||||
impl From<JsValue> for #name {
|
||||
fn from(obj: JsValue) -> #name {
|
||||
#name { obj }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<JsValue> for #name {
|
||||
fn as_ref(&self) -> &JsValue { &self.obj }
|
||||
}
|
||||
|
||||
impl AsMut<JsValue> for #name {
|
||||
fn as_mut(&mut self) -> &mut JsValue { &mut self.obj }
|
||||
}
|
||||
|
||||
impl From<#name> for JsValue {
|
||||
fn from(obj: #name) -> JsValue {
|
||||
obj.obj
|
||||
}
|
||||
}
|
||||
|
||||
impl JsCast for #name {
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
fn instanceof(val: &JsValue) -> bool {
|
||||
#[link(wasm_import_module = "__wbindgen_placeholder__")]
|
||||
extern {
|
||||
fn #instanceof_shim(val: u32) -> u32;
|
||||
}
|
||||
unsafe {
|
||||
let idx = val.into_abi(&mut GlobalStack::new());
|
||||
#instanceof_shim(idx) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
|
||||
fn instanceof(val: &JsValue) -> bool {
|
||||
drop(val);
|
||||
panic!("cannot check instanceof on non-wasm targets");
|
||||
}
|
||||
|
||||
fn unchecked_from_js(val: JsValue) -> Self {
|
||||
#name { obj: val }
|
||||
}
|
||||
|
||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
|
||||
// Should be safe because `#name` is a transparent
|
||||
// wrapper around `val`
|
||||
unsafe { &*(val as *const JsValue as *const #name) }
|
||||
}
|
||||
|
||||
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self {
|
||||
// Should be safe because `#name` is a transparent
|
||||
// wrapper around `val`
|
||||
unsafe { &mut *(val as *mut JsValue as *mut #name) }
|
||||
}
|
||||
}
|
||||
|
||||
()
|
||||
};
|
||||
}).to_tokens(tokens);
|
||||
|
@@ -1755,7 +1755,14 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
format!("failed to generate bindings for JS import `{}`", s.name)
|
||||
})?;
|
||||
}
|
||||
shared::ImportKind::Type(_) => {}
|
||||
shared::ImportKind::Type(ref ty) => {
|
||||
self.generate_import_type(import, ty).with_context(|_| {
|
||||
format!(
|
||||
"failed to generate bindings for JS import `{}`",
|
||||
ty.name,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
shared::ImportKind::Enum(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
@@ -1936,6 +1943,27 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_import_type(
|
||||
&mut self,
|
||||
info: &shared::Import,
|
||||
import: &shared::ImportType,
|
||||
) -> Result<(), Error> {
|
||||
if !self.cx.wasm_import_needed(&import.instanceof_shim) {
|
||||
return Ok(());
|
||||
}
|
||||
let name = self.import_name(info, &import.name)?;
|
||||
self.cx.expose_get_object();
|
||||
let body = format!("
|
||||
function(idx) {{
|
||||
return getObject(idx) instanceof {} ? 1 : 0;
|
||||
}}
|
||||
",
|
||||
name,
|
||||
);
|
||||
self.cx.export(&import.instanceof_shim, &body, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_enum(&mut self, enum_: &shared::Enum) {
|
||||
let mut variants = String::new();
|
||||
|
||||
|
@@ -524,11 +524,13 @@ impl ConvertToAst<()> for syn::ForeignItemType {
|
||||
type Target = ast::ImportKind;
|
||||
|
||||
fn convert(self, (): ()) -> Result<Self::Target, Diagnostic> {
|
||||
let shim = format!("__wbg_instanceof_{}_{}", self.ident, ShortHash(&self.ident));
|
||||
Ok(ast::ImportKind::Type(ast::ImportType {
|
||||
vis: self.vis,
|
||||
name: self.ident,
|
||||
attrs: self.attrs,
|
||||
doc_comment: None,
|
||||
instanceof_shim: shim,
|
||||
name: self.ident,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
pub const SCHEMA_VERSION: &str = "7";
|
||||
pub const SCHEMA_VERSION: &str = "8";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ProgramOnlySchema {
|
||||
@@ -81,7 +81,10 @@ pub struct ImportStatic {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ImportType {}
|
||||
pub struct ImportType {
|
||||
pub name: String,
|
||||
pub instanceof_shim: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ImportEnum {}
|
||||
|
@@ -246,6 +246,7 @@ impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> {
|
||||
name: rust_ident(camel_case_ident(self.identifier.0).as_str()),
|
||||
attrs: Vec::new(),
|
||||
doc_comment,
|
||||
instanceof_shim: format!("__widl_instanceof_{}", self.name),
|
||||
}),
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user