mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 02:00:51 +00:00
Add customisable is_type_of
This commit is contained in:
parent
4211fcd992
commit
cb880bdbff
@ -183,6 +183,7 @@ pub struct ImportType {
|
||||
pub attrs: Vec<syn::Attribute>,
|
||||
pub doc_comment: Option<String>,
|
||||
pub instanceof_shim: String,
|
||||
pub is_type_of: Option<syn::Expr>,
|
||||
pub extends: Vec<syn::Path>,
|
||||
pub vendor_prefixes: Vec<Ident>,
|
||||
}
|
||||
|
@ -588,6 +588,13 @@ impl ToTokens for ast::ImportType {
|
||||
}
|
||||
};
|
||||
|
||||
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)*
|
||||
@ -720,6 +727,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.into() }
|
||||
|
@ -126,7 +126,7 @@ extern "C" {
|
||||
// Array
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = Object)]
|
||||
#[wasm_bindgen(extends = Object, is_type_of = Array::is_array)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub type Array;
|
||||
|
||||
@ -466,7 +466,7 @@ extern "C" {
|
||||
// Boolean
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = Object)]
|
||||
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_bool().is_some())]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub type Boolean;
|
||||
|
||||
@ -801,7 +801,7 @@ extern "C" {
|
||||
// Function
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = Object)]
|
||||
#[wasm_bindgen(extends = Object, is_type_of = JsValue::is_function)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub type Function;
|
||||
|
||||
@ -897,11 +897,7 @@ impl Function {
|
||||
/// If this JS value is not an instance of a function then this returns
|
||||
/// `None`.
|
||||
pub fn try_from(val: &JsValue) -> Option<&Function> {
|
||||
if val.is_function() {
|
||||
Some(val.unchecked_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
val.dyn_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1141,7 +1137,10 @@ pub fn try_iter(val: &JsValue) -> Result<Option<IntoIter>, JsValue> {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let iter_fn: Function = iter_fn.unchecked_into();
|
||||
let iter_fn: Function = match iter_fn.dyn_into() {
|
||||
Ok(iter_fn) => iter_fn,
|
||||
Err(_) => return Ok(None)
|
||||
};
|
||||
let it = iter_fn.call0(val)?;
|
||||
if !it.is_object() {
|
||||
return Ok(None);
|
||||
@ -1434,7 +1433,7 @@ extern "C" {
|
||||
// Number.
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = Object)]
|
||||
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some())]
|
||||
#[derive(Clone)]
|
||||
pub type Number;
|
||||
|
||||
@ -3127,7 +3126,7 @@ extern "C" {
|
||||
// JsString
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_name = String, extends = Object)]
|
||||
#[wasm_bindgen(js_name = String, extends = Object, is_type_of = JsValue::is_string)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub type JsString;
|
||||
|
||||
@ -3587,11 +3586,7 @@ impl JsString {
|
||||
/// If this JS value is not an instance of a string then this returns
|
||||
/// `None`.
|
||||
pub fn try_from(val: &JsValue) -> Option<&JsString> {
|
||||
if val.is_string() {
|
||||
Some(val.unchecked_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
val.dyn_ref()
|
||||
}
|
||||
|
||||
/// Returns whether this string is a valid UTF-16 string.
|
||||
@ -3683,6 +3678,7 @@ impl fmt::Debug for JsString {
|
||||
// Symbol
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(is_type_of = JsValue::is_symbol)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub type Symbol;
|
||||
|
||||
|
@ -45,6 +45,7 @@ macro_rules! attrgen {
|
||||
(readonly, Readonly(Span)),
|
||||
(js_name, JsName(Span, String, Span)),
|
||||
(js_class, JsClass(Span, String, Span)),
|
||||
(is_type_of, IsTypeOf(Span, syn::Expr)),
|
||||
(extends, Extends(Span, syn::Path)),
|
||||
(vendor_prefix, VendorPrefix(Span, Ident)),
|
||||
(variadic, Variadic(Span)),
|
||||
@ -240,6 +241,11 @@ impl Parse for BindgenAttr {
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, syn::Expr)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
|
||||
});
|
||||
|
||||
(@parser $variant:ident(Span, String, Span)) => ({
|
||||
input.parse::<Token![=]>()?;
|
||||
let (val, span) = match input.parse::<syn::LitStr>() {
|
||||
@ -515,6 +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 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();
|
||||
@ -537,6 +544,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
|
||||
attrs: self.attrs,
|
||||
doc_comment: None,
|
||||
instanceof_shim: shim,
|
||||
is_type_of,
|
||||
rust_name: self.ident,
|
||||
js_name,
|
||||
extends,
|
||||
|
@ -514,6 +514,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
attrs,
|
||||
doc_comment: None,
|
||||
instanceof_shim: format!("__widl_instanceof_{}", name),
|
||||
is_type_of: None,
|
||||
extends: Vec::new(),
|
||||
vendor_prefixes: Vec::new(),
|
||||
};
|
||||
|
16
src/cast.rs
16
src/cast.rs
@ -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)
|
||||
@ -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
|
||||
@ -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`
|
||||
///
|
||||
|
Loading…
x
Reference in New Issue
Block a user