Skip to content

Commit cb880bd

Browse files
committed
Add customisable is_type_of
1 parent 4211fcd commit cb880bd

File tree

6 files changed

+43
-20
lines changed

6 files changed

+43
-20
lines changed

crates/backend/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub struct ImportType {
183183
pub attrs: Vec<syn::Attribute>,
184184
pub doc_comment: Option<String>,
185185
pub instanceof_shim: String,
186+
pub is_type_of: Option<syn::Expr>,
186187
pub extends: Vec<syn::Path>,
187188
pub vendor_prefixes: Vec<Ident>,
188189
}

crates/backend/src/codegen.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,13 @@ impl ToTokens for ast::ImportType {
588588
}
589589
};
590590

591+
let is_type_of = self.is_type_of.as_ref().map(|is_type_of| quote! {
592+
fn is_type_of(val: &JsValue) -> bool {
593+
let is_type_of: fn(&JsValue) -> bool = #is_type_of;
594+
is_type_of(val)
595+
}
596+
});
597+
591598
(quote! {
592599
#[allow(bad_style)]
593600
#(#attrs)*
@@ -720,6 +727,8 @@ impl ToTokens for ast::ImportType {
720727
panic!("cannot check instanceof on non-wasm targets");
721728
}
722729

730+
#is_type_of
731+
723732
#[inline]
724733
fn unchecked_from_js(val: JsValue) -> Self {
725734
#rust_name { obj: val.into() }

crates/js-sys/src/lib.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ extern "C" {
126126
// Array
127127
#[wasm_bindgen]
128128
extern "C" {
129-
#[wasm_bindgen(extends = Object)]
129+
#[wasm_bindgen(extends = Object, is_type_of = Array::is_array)]
130130
#[derive(Clone, Debug, PartialEq, Eq)]
131131
pub type Array;
132132

@@ -466,7 +466,7 @@ extern "C" {
466466
// Boolean
467467
#[wasm_bindgen]
468468
extern "C" {
469-
#[wasm_bindgen(extends = Object)]
469+
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_bool().is_some())]
470470
#[derive(Clone, PartialEq, Eq)]
471471
pub type Boolean;
472472

@@ -801,7 +801,7 @@ extern "C" {
801801
// Function
802802
#[wasm_bindgen]
803803
extern "C" {
804-
#[wasm_bindgen(extends = Object)]
804+
#[wasm_bindgen(extends = Object, is_type_of = JsValue::is_function)]
805805
#[derive(Clone, Debug, PartialEq, Eq)]
806806
pub type Function;
807807

@@ -897,11 +897,7 @@ impl Function {
897897
/// If this JS value is not an instance of a function then this returns
898898
/// `None`.
899899
pub fn try_from(val: &JsValue) -> Option<&Function> {
900-
if val.is_function() {
901-
Some(val.unchecked_ref())
902-
} else {
903-
None
904-
}
900+
val.dyn_ref()
905901
}
906902
}
907903

@@ -1141,7 +1137,10 @@ pub fn try_iter(val: &JsValue) -> Result<Option<IntoIter>, JsValue> {
11411137
return Ok(None);
11421138
}
11431139

1144-
let iter_fn: Function = iter_fn.unchecked_into();
1140+
let iter_fn: Function = match iter_fn.dyn_into() {
1141+
Ok(iter_fn) => iter_fn,
1142+
Err(_) => return Ok(None)
1143+
};
11451144
let it = iter_fn.call0(val)?;
11461145
if !it.is_object() {
11471146
return Ok(None);
@@ -1434,7 +1433,7 @@ extern "C" {
14341433
// Number.
14351434
#[wasm_bindgen]
14361435
extern "C" {
1437-
#[wasm_bindgen(extends = Object)]
1436+
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some())]
14381437
#[derive(Clone)]
14391438
pub type Number;
14401439

@@ -3127,7 +3126,7 @@ extern "C" {
31273126
// JsString
31283127
#[wasm_bindgen]
31293128
extern "C" {
3130-
#[wasm_bindgen(js_name = String, extends = Object)]
3129+
#[wasm_bindgen(js_name = String, extends = Object, is_type_of = JsValue::is_string)]
31313130
#[derive(Clone, PartialEq, Eq)]
31323131
pub type JsString;
31333132

@@ -3587,11 +3586,7 @@ impl JsString {
35873586
/// If this JS value is not an instance of a string then this returns
35883587
/// `None`.
35893588
pub fn try_from(val: &JsValue) -> Option<&JsString> {
3590-
if val.is_string() {
3591-
Some(val.unchecked_ref())
3592-
} else {
3593-
None
3594-
}
3589+
val.dyn_ref()
35953590
}
35963591

35973592
/// Returns whether this string is a valid UTF-16 string.
@@ -3683,6 +3678,7 @@ impl fmt::Debug for JsString {
36833678
// Symbol
36843679
#[wasm_bindgen]
36853680
extern "C" {
3681+
#[wasm_bindgen(is_type_of = JsValue::is_symbol)]
36863682
#[derive(Clone, Debug)]
36873683
pub type Symbol;
36883684

crates/macro-support/src/parser.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ macro_rules! attrgen {
4545
(readonly, Readonly(Span)),
4646
(js_name, JsName(Span, String, Span)),
4747
(js_class, JsClass(Span, String, Span)),
48+
(is_type_of, IsTypeOf(Span, syn::Expr)),
4849
(extends, Extends(Span, syn::Path)),
4950
(vendor_prefix, VendorPrefix(Span, Ident)),
5051
(variadic, Variadic(Span)),
@@ -240,6 +241,11 @@ impl Parse for BindgenAttr {
240241
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
241242
});
242243

244+
(@parser $variant:ident(Span, syn::Expr)) => ({
245+
input.parse::<Token![=]>()?;
246+
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
247+
});
248+
243249
(@parser $variant:ident(Span, String, Span)) => ({
244250
input.parse::<Token![=]>()?;
245251
let (val, span) = match input.parse::<syn::LitStr>() {
@@ -515,6 +521,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
515521
.js_name()
516522
.map(|s| s.0)
517523
.map_or_else(|| self.ident.to_string(), |s| s.to_string());
524+
let is_type_of = attrs.is_type_of().cloned();
518525
let shim = format!("__wbg_instanceof_{}_{}", self.ident, ShortHash(&self.ident));
519526
let mut extends = Vec::new();
520527
let mut vendor_prefixes = Vec::new();
@@ -537,6 +544,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
537544
attrs: self.attrs,
538545
doc_comment: None,
539546
instanceof_shim: shim,
547+
is_type_of,
540548
rust_name: self.ident,
541549
js_name,
542550
extends,

crates/webidl/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ impl<'src> FirstPassRecord<'src> {
514514
attrs,
515515
doc_comment: None,
516516
instanceof_shim: format!("__widl_instanceof_{}", name),
517+
is_type_of: None,
517518
extends: Vec::new(),
518519
vendor_prefixes: Vec::new(),
519520
};

src/cast.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ where
3030
/// Performs a dynamic cast (checked at runtime) of this value into the
3131
/// target type `T`.
3232
///
33-
/// This method will return `Err(self)` if `self.is_instance_of::<T>()`
33+
/// This method will return `Err(self)` if `T::is_type_of(self)`
3434
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
3535
/// an unchecked cast (verified correct via the `instanceof` operation).
3636
fn dyn_into<T>(self) -> Result<T, Self>
3737
where
3838
T: JsCast,
3939
{
40-
if self.is_instance_of::<T>() {
40+
if T::is_type_of(self.as_ref()) {
4141
Ok(self.unchecked_into())
4242
} else {
4343
Err(self)
@@ -47,14 +47,14 @@ where
4747
/// Performs a dynamic cast (checked at runtime) of this value into the
4848
/// target type `T`.
4949
///
50-
/// This method will return `None` if `self.is_instance_of::<T>()`
50+
/// This method will return `None` if `T::is_type_of(self)`
5151
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
5252
/// with an unchecked cast (verified correct via the `instanceof` operation).
5353
fn dyn_ref<T>(&self) -> Option<&T>
5454
where
5555
T: JsCast,
5656
{
57-
if self.is_instance_of::<T>() {
57+
if T::is_type_of(self.as_ref()) {
5858
Some(self.unchecked_ref())
5959
} else {
6060
None
@@ -100,6 +100,14 @@ where
100100
/// won't need to call this.
101101
fn instanceof(val: &JsValue) -> bool;
102102

103+
/// Performs a dynamic check to see whether the `JsValue` provided
104+
/// is a value of this type.
105+
///
106+
/// Unlike `instanceof`, this can be specialised to use a custom check.
107+
fn is_type_of(val: &JsValue) -> bool {
108+
Self::instanceof(val)
109+
}
110+
103111
/// Performs a zero-cost unchecked conversion from a `JsValue` into an
104112
/// instance of `Self`
105113
///

0 commit comments

Comments
 (0)