Skip to content

Commit

Permalink
Separate custom is_type_of from regular instanceof
Browse files Browse the repository at this point in the history
  • Loading branch information
RReverser committed Apr 9, 2019
1 parent bd3b2ab commit e68c2f8
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 37 deletions.
2 changes: 1 addition & 1 deletion crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pub struct ImportType {
pub attrs: Vec<syn::Attribute>,
pub doc_comment: Option<String>,
pub instanceof_shim: String,
pub instanceof: Option<syn::Expr>,
pub is_type_of: Option<syn::Expr>,
pub extends: Vec<syn::Path>,
pub vendor_prefixes: Vec<Ident>,
}
Expand Down
37 changes: 16 additions & 21 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,27 +577,13 @@ impl ToTokens for ast::ImportType {
};
let const_name = format!("__wbg_generated_const_{}", rust_name);
let const_name = Ident::new(&const_name, Span::call_site());
let instanceof = match &self.instanceof {
Some(instanceof) => {
quote! {
let instanceof: fn(&JsValue) -> bool = #instanceof;
instanceof(val)
}
}
None => {
let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
quote! {
#[link(wasm_import_module = "__wbindgen_placeholder__")]
extern "C" {
fn #instanceof_shim(val: u32) -> u32;
}
unsafe {
let idx = val.into_abi(&mut wasm_bindgen::convert::GlobalStack::new());
#instanceof_shim(idx) != 0
}
}
let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
let is_type_of = self.is_type_of.as_ref().map(|is_type_of| quote! {
fn is_type_of(val: &JsValue) -> bool {
let is_type_of: fn(&JsValue) -> bool = #is_type_of;
is_type_of(val)
}
};
});
(quote! {
#[allow(bad_style)]
#(#attrs)*
Expand Down Expand Up @@ -705,7 +691,14 @@ impl ToTokens for ast::ImportType {
impl JsCast for #rust_name {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
fn instanceof(val: &JsValue) -> bool {
#instanceof
#[link(wasm_import_module = "__wbindgen_placeholder__")]
extern "C" {
fn #instanceof_shim(val: u32) -> u32;
}
unsafe {
let idx = val.into_abi(&mut wasm_bindgen::convert::GlobalStack::new());
#instanceof_shim(idx) != 0
}
}

#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
Expand All @@ -714,6 +707,8 @@ impl ToTokens for ast::ImportType {
panic!("cannot check instanceof on non-wasm targets");
}

#is_type_of

#[inline]
fn unchecked_from_js(val: JsValue) -> Self {
#rust_name { obj: val }
Expand Down
12 changes: 6 additions & 6 deletions crates/js-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ extern "C" {
// Array
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object, instanceof = Array::is_array)]
#[wasm_bindgen(extends = Object, is_type_of = Array::is_array)]
#[derive(Clone, Debug)]
pub type Array;

Expand Down Expand Up @@ -466,7 +466,7 @@ extern "C" {
// Boolean
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object, instanceof = |v| v.as_bool().is_some())]
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_bool().is_some())]
#[derive(Clone, Debug)]
pub type Boolean;

Expand Down Expand Up @@ -773,7 +773,7 @@ extern "C" {
// Function
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object, instanceof = JsValue::is_function)]
#[wasm_bindgen(extends = Object, is_type_of = JsValue::is_function)]
#[derive(Clone, Debug)]
pub type Function;

Expand Down Expand Up @@ -1404,7 +1404,7 @@ extern "C" {
// Number.
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object, instanceof = |v| v.as_f64().is_some())]
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some())]
#[derive(Clone, Debug)]
pub type Number;

Expand Down Expand Up @@ -3055,7 +3055,7 @@ extern "C" {
// JsString
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = String, extends = Object, instanceof = JsValue::is_string)]
#[wasm_bindgen(js_name = String, extends = Object, is_type_of = JsValue::is_string)]
#[derive(Clone)]
pub type JsString;

Expand Down Expand Up @@ -3613,7 +3613,7 @@ impl fmt::Debug for JsString {
// Symbol
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(instanceof = JsValue::is_symbol)]
#[wasm_bindgen(is_type_of = JsValue::is_symbol)]
#[derive(Clone, Debug)]
pub type Symbol;

Expand Down
8 changes: 3 additions & 5 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ macro_rules! attrgen {
(readonly, Readonly(Span)),
(js_name, JsName(Span, String, Span)),
(js_class, JsClass(Span, String, Span)),
(instanceof, Instanceof(Span, syn::Expr)),
(is_type_of, IsTypeOf(Span, syn::Expr)),
(extends, Extends(Span, syn::Path)),
(vendor_prefix, VendorPrefix(Span, Ident)),
(variadic, Variadic(Span)),
Expand Down Expand Up @@ -521,9 +521,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
.js_name()
.map(|s| s.0)
.map_or_else(|| self.ident.to_string(), |s| s.to_string());
let instanceof = attrs
.instanceof()
.cloned();
let is_type_of = attrs.is_type_of().cloned();
let shim = format!("__wbg_instanceof_{}_{}", self.ident, ShortHash(&self.ident));
let mut extends = Vec::new();
let mut vendor_prefixes = Vec::new();
Expand All @@ -546,7 +544,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
attrs: self.attrs,
doc_comment: None,
instanceof_shim: shim,
instanceof,
is_type_of,
rust_name: self.ident,
js_name,
extends,
Expand Down
16 changes: 12 additions & 4 deletions src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ where
/// Performs a dynamic cast (checked at runtime) of this value into the
/// target type `T`.
///
/// This method will return `Err(self)` if `self.is_instance_of::<T>()`
/// This method will return `Err(self)` if `T::is_type_of(self)`
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
/// an unchecked cast (verified correct via the `instanceof` operation).
fn dyn_into<T>(self) -> Result<T, Self>
where
T: JsCast,
{
if self.is_instance_of::<T>() {
if T::is_type_of(self.as_ref()) {
Ok(self.unchecked_into())
} else {
Err(self)
Expand All @@ -47,14 +47,14 @@ where
/// Performs a dynamic cast (checked at runtime) of this value into the
/// target type `T`.
///
/// This method will return `None` if `self.is_instance_of::<T>()`
/// This method will return `None` if `T::is_type_of(self)`
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
/// with an unchecked cast (verified correct via the `instanceof` operation).
fn dyn_ref<T>(&self) -> Option<&T>
where
T: JsCast,
{
if self.is_instance_of::<T>() {
if T::is_type_of(self.as_ref()) {
Some(self.unchecked_ref())
} else {
None
Expand Down Expand Up @@ -100,6 +100,14 @@ where
/// won't need to call this.
fn instanceof(val: &JsValue) -> bool;

/// Performs a dynamic check to see whether the `JsValue` provided
/// is a value of this type.
///
/// Unlike `instanceof`, this can be specialised to use a custom check.
fn is_type_of(val: &JsValue) -> bool {
Self::instanceof(val)
}

/// Performs a zero-cost unchecked conversion from a `JsValue` into an
/// instance of `Self`
///
Expand Down

0 comments on commit e68c2f8

Please sign in to comment.