mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-17 23:11:23 +00:00
Merge pull request #652 from afdw/master
Add support for getters, setters and deleters
This commit is contained in:
@ -105,8 +105,11 @@ pub struct Operation {
|
|||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
pub enum OperationKind {
|
pub enum OperationKind {
|
||||||
Regular,
|
Regular,
|
||||||
Setter(Option<Ident>),
|
|
||||||
Getter(Option<Ident>),
|
Getter(Option<Ident>),
|
||||||
|
Setter(Option<Ident>),
|
||||||
|
IndexingGetter,
|
||||||
|
IndexingSetter,
|
||||||
|
IndexingDeleter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
@ -369,6 +372,9 @@ impl ImportFunction {
|
|||||||
s.unwrap_or_else(|| self.infer_setter_property()),
|
s.unwrap_or_else(|| self.infer_setter_property()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
OperationKind::IndexingGetter => shared::OperationKind::IndexingGetter,
|
||||||
|
OperationKind::IndexingSetter => shared::OperationKind::IndexingSetter,
|
||||||
|
OperationKind::IndexingDeleter => shared::OperationKind::IndexingDeleter,
|
||||||
};
|
};
|
||||||
shared::MethodKind::Operation(shared::Operation { is_static, kind })
|
shared::MethodKind::Operation(shared::Operation { is_static, kind })
|
||||||
}
|
}
|
||||||
|
@ -1808,18 +1808,6 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
let location = if *is_static { &class } else { "this" };
|
let location = if *is_static { &class } else { "this" };
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
shared::OperationKind::Getter(g) => format!(
|
|
||||||
"function() {{
|
|
||||||
return {}.{};
|
|
||||||
}}",
|
|
||||||
location, g
|
|
||||||
),
|
|
||||||
shared::OperationKind::Setter(s) => format!(
|
|
||||||
"function(y) {{
|
|
||||||
{}.{} = y;
|
|
||||||
}}",
|
|
||||||
location, s
|
|
||||||
),
|
|
||||||
shared::OperationKind::Regular => {
|
shared::OperationKind::Regular => {
|
||||||
let nargs = descriptor.unwrap_function().arguments.len();
|
let nargs = descriptor.unwrap_function().arguments.len();
|
||||||
let mut s = format!("function(");
|
let mut s = format!("function(");
|
||||||
@ -1841,11 +1829,44 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
s.push_str(");\n}");
|
s.push_str(");\n}");
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
shared::OperationKind::Getter(g) => format!(
|
||||||
|
"function() {{
|
||||||
|
return {}.{};
|
||||||
|
}}",
|
||||||
|
location, g
|
||||||
|
),
|
||||||
|
shared::OperationKind::Setter(s) => format!(
|
||||||
|
"function(y) {{
|
||||||
|
{}.{} = y;
|
||||||
|
}}",
|
||||||
|
location, s
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingGetter => format!(
|
||||||
|
"function(y) {{
|
||||||
|
return {}[y];
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingSetter => format!(
|
||||||
|
"function(y, z) {{
|
||||||
|
{}[y] = z;
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingDeleter => format!(
|
||||||
|
"function(y) {{
|
||||||
|
delete {}[y];
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let location = if *is_static { "" } else { ".prototype" };
|
let location = if *is_static { "" } else { ".prototype" };
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
|
shared::OperationKind::Regular => {
|
||||||
|
format!("{}{}.{}", class, location, import.function.name)
|
||||||
|
}
|
||||||
shared::OperationKind::Getter(g) => {
|
shared::OperationKind::Getter(g) => {
|
||||||
self.cx.expose_get_inherited_descriptor();
|
self.cx.expose_get_inherited_descriptor();
|
||||||
format!(
|
format!(
|
||||||
@ -1860,9 +1881,9 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
class, location, s,
|
class, location, s,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
shared::OperationKind::Regular => {
|
shared::OperationKind::IndexingGetter => panic!("indexing getter should be structural"),
|
||||||
format!("{}{}.{}", class, location, import.function.name)
|
shared::OperationKind::IndexingSetter => panic!("indexing setter should be structural"),
|
||||||
}
|
shared::OperationKind::IndexingDeleter => panic!("indexing deleter should be structural"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,6 +121,30 @@ impl BindgenAttrs {
|
|||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the indexing getter attributes is present
|
||||||
|
fn indexing_getter(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match *a {
|
||||||
|
BindgenAttr::IndexingGetter => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the indexing setter attributes is present
|
||||||
|
fn indexing_setter(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match *a {
|
||||||
|
BindgenAttr::IndexingSetter => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the indexing deleter attributes is present
|
||||||
|
fn indexing_deleter(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match *a {
|
||||||
|
BindgenAttr::IndexingDeleter => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the structural attributes is present
|
/// Whether the structural attributes is present
|
||||||
fn structural(&self) -> bool {
|
fn structural(&self) -> bool {
|
||||||
self.attrs.iter().any(|a| match *a {
|
self.attrs.iter().any(|a| match *a {
|
||||||
@ -186,6 +210,9 @@ pub enum BindgenAttr {
|
|||||||
Module(String),
|
Module(String),
|
||||||
Getter(Option<Ident>),
|
Getter(Option<Ident>),
|
||||||
Setter(Option<Ident>),
|
Setter(Option<Ident>),
|
||||||
|
IndexingGetter,
|
||||||
|
IndexingSetter,
|
||||||
|
IndexingDeleter,
|
||||||
Structural,
|
Structural,
|
||||||
Readonly,
|
Readonly,
|
||||||
JsName(String),
|
JsName(String),
|
||||||
@ -227,6 +254,12 @@ impl syn::synom::Synom for BindgenAttr {
|
|||||||
(val)
|
(val)
|
||||||
)=> { BindgenAttr::Setter }
|
)=> { BindgenAttr::Setter }
|
||||||
|
|
|
|
||||||
|
call!(term, "indexing_getter") => { |_| BindgenAttr::IndexingGetter }
|
||||||
|
|
|
||||||
|
call!(term, "indexing_setter") => { |_| BindgenAttr::IndexingSetter }
|
||||||
|
|
|
||||||
|
call!(term, "indexing_deleter") => { |_| BindgenAttr::IndexingDeleter }
|
||||||
|
|
|
||||||
call!(term, "structural") => { |_| BindgenAttr::Structural }
|
call!(term, "structural") => { |_| BindgenAttr::Structural }
|
||||||
|
|
|
|
||||||
call!(term, "readonly") => { |_| BindgenAttr::Readonly }
|
call!(term, "readonly") => { |_| BindgenAttr::Readonly }
|
||||||
@ -381,6 +414,15 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
if let Some(s) = opts.setter() {
|
if let Some(s) = opts.setter() {
|
||||||
operation_kind = ast::OperationKind::Setter(s);
|
operation_kind = ast::OperationKind::Setter(s);
|
||||||
}
|
}
|
||||||
|
if opts.indexing_getter() {
|
||||||
|
operation_kind = ast::OperationKind::IndexingGetter;
|
||||||
|
}
|
||||||
|
if opts.indexing_setter() {
|
||||||
|
operation_kind = ast::OperationKind::IndexingSetter;
|
||||||
|
}
|
||||||
|
if opts.indexing_deleter() {
|
||||||
|
operation_kind = ast::OperationKind::IndexingDeleter;
|
||||||
|
}
|
||||||
|
|
||||||
let kind = if opts.method() {
|
let kind = if opts.method() {
|
||||||
let class = wasm
|
let class = wasm
|
||||||
|
@ -69,6 +69,9 @@ pub enum OperationKind {
|
|||||||
Regular,
|
Regular,
|
||||||
Getter(String),
|
Getter(String),
|
||||||
Setter(String),
|
Setter(String),
|
||||||
|
IndexingGetter,
|
||||||
|
IndexingSetter,
|
||||||
|
IndexingDeleter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -93,6 +93,20 @@ global.GlobalMethod = class GlobalMethod {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
global.Indexing = function () {
|
||||||
|
return new Proxy({}, {
|
||||||
|
get(obj, prop) {
|
||||||
|
return obj.hasOwnProperty(prop) ? obj[prop] : -1;
|
||||||
|
},
|
||||||
|
set(obj, prop, value) {
|
||||||
|
obj[prop] = value;
|
||||||
|
},
|
||||||
|
deleteProperty(obj, prop) {
|
||||||
|
delete obj[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
global.PartialInterface = class PartialInterface {
|
global.PartialInterface = class PartialInterface {
|
||||||
get un() {
|
get un() {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -65,7 +65,17 @@ fn optional_method() {
|
|||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn global_method() {
|
fn global_method() {
|
||||||
let f = GlobalMethod::new().unwrap();
|
let f = GlobalMethod::new().unwrap();
|
||||||
assert!(f.m() == 123);
|
assert_eq!(f.m(), 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn indexing() {
|
||||||
|
let f = Indexing::new().unwrap();
|
||||||
|
assert_eq!(f.get(123), -1);
|
||||||
|
f.set(123, 456);
|
||||||
|
assert_eq!(f.get(123), 456);
|
||||||
|
f.delete(123);
|
||||||
|
assert_eq!(f.get(123), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
|
7
crates/webidl-tests/simple.webidl
vendored
7
crates/webidl-tests/simple.webidl
vendored
@ -40,6 +40,13 @@ interface GlobalMethod {
|
|||||||
octet m();
|
octet m();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[Constructor()]
|
||||||
|
interface Indexing {
|
||||||
|
getter short (unsigned long index);
|
||||||
|
setter void (unsigned long index, short value);
|
||||||
|
deleter void (unsigned long index);
|
||||||
|
};
|
||||||
|
|
||||||
[Constructor()]
|
[Constructor()]
|
||||||
interface Unforgeable {
|
interface Unforgeable {
|
||||||
[Unforgeable] readonly attribute short uno;
|
[Unforgeable] readonly attribute short uno;
|
||||||
|
@ -41,7 +41,10 @@ pub(crate) struct InterfaceData<'src> {
|
|||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub(crate) enum OperationId<'src> {
|
pub(crate) enum OperationId<'src> {
|
||||||
Constructor,
|
Constructor,
|
||||||
Operation(Option<&'src str>)
|
Operation(Option<&'src str>),
|
||||||
|
IndexingGetter,
|
||||||
|
IndexingSetter,
|
||||||
|
IndexingDeleter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -243,7 +246,7 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::InterfaceMember<'sr
|
|||||||
|
|
||||||
impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> {
|
impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> {
|
||||||
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
|
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
|
||||||
if self.specials.len() > 0 {
|
if !self.specials.is_empty() && self.specials.len() != 1 {
|
||||||
warn!("Unsupported webidl operation {:?}", self);
|
warn!("Unsupported webidl operation {:?}", self);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
@ -254,7 +257,16 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceM
|
|||||||
first_pass_operation(
|
first_pass_operation(
|
||||||
record,
|
record,
|
||||||
self_name,
|
self_name,
|
||||||
OperationId::Operation(self.identifier.map(|s| s.0)),
|
match self.identifier.map(|s| s.0) {
|
||||||
|
None => match self.specials.get(0) {
|
||||||
|
None => OperationId::Operation(None),
|
||||||
|
Some(weedle::interface::Special::Getter(weedle::term::Getter)) => OperationId::IndexingGetter,
|
||||||
|
Some(weedle::interface::Special::Setter(weedle::term::Setter)) => OperationId::IndexingSetter,
|
||||||
|
Some(weedle::interface::Special::Deleter(weedle::term::Deleter)) => OperationId::IndexingDeleter,
|
||||||
|
Some(weedle::interface::Special::LegacyCaller(weedle::term::LegacyCaller)) => return Ok(()),
|
||||||
|
},
|
||||||
|
Some(ref name) => OperationId::Operation(Some(name.clone())),
|
||||||
|
},
|
||||||
&self.args.body.list,
|
&self.args.body.list,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for Extend
|
|||||||
let mut add_constructor = |arguments: &[Argument], class: &str| {
|
let mut add_constructor = |arguments: &[Argument], class: &str| {
|
||||||
let (overloaded, same_argument_names) = first_pass.get_operation_overloading(
|
let (overloaded, same_argument_names) = first_pass.get_operation_overloading(
|
||||||
arguments,
|
arguments,
|
||||||
::first_pass::OperationId::Constructor,
|
&::first_pass::OperationId::Constructor,
|
||||||
interface.identifier.0,
|
interface.identifier.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -644,18 +644,32 @@ fn member_operation<'src>(
|
|||||||
Some(Static(_)) => true,
|
Some(Static(_)) => true,
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
if specials.len() > 0 {
|
|
||||||
warn!("Unsupported specials on type {:?}", (self_name, identifier));
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
first_pass
|
first_pass
|
||||||
.create_basic_method(
|
.create_basic_method(
|
||||||
args,
|
args,
|
||||||
identifier.map(|s| s.0),
|
match identifier.map(|s| s.0) {
|
||||||
|
None if specials.is_empty() => ::first_pass::OperationId::Operation(None),
|
||||||
|
None if specials.len() == 1 => match specials[0] {
|
||||||
|
weedle::interface::Special::Getter(weedle::term::Getter) => ::first_pass::OperationId::IndexingGetter,
|
||||||
|
weedle::interface::Special::Setter(weedle::term::Setter) => ::first_pass::OperationId::IndexingSetter,
|
||||||
|
weedle::interface::Special::Deleter(weedle::term::Deleter) => ::first_pass::OperationId::IndexingDeleter,
|
||||||
|
weedle::interface::Special::LegacyCaller(weedle::term::LegacyCaller) => return Ok(()),
|
||||||
|
},
|
||||||
|
Some(ref name) if specials.is_empty() => ::first_pass::OperationId::Operation(Some(name.clone())),
|
||||||
|
_ => {
|
||||||
|
warn!("Unsupported specials on type {:?}", (self_name, identifier));
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
return_type,
|
return_type,
|
||||||
self_name,
|
self_name,
|
||||||
statik,
|
statik,
|
||||||
|
specials.len() == 1 || first_pass
|
||||||
|
.interfaces
|
||||||
|
.get(self_name)
|
||||||
|
.map(|interface_data| interface_data.global)
|
||||||
|
.unwrap_or(false),
|
||||||
util::throws(attrs),
|
util::throws(attrs),
|
||||||
)
|
)
|
||||||
.map(wrap_import_function)
|
.map(wrap_import_function)
|
||||||
|
@ -910,24 +910,31 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
pub fn create_basic_method(
|
pub fn create_basic_method(
|
||||||
&self,
|
&self,
|
||||||
arguments: &[weedle::argument::Argument],
|
arguments: &[weedle::argument::Argument],
|
||||||
name: Option<&str>,
|
operation_id: ::first_pass::OperationId,
|
||||||
return_type: &weedle::types::ReturnType,
|
return_type: &weedle::types::ReturnType,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
is_static: bool,
|
is_static: bool,
|
||||||
|
structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
||||||
arguments,
|
arguments,
|
||||||
::first_pass::OperationId::Operation(name),
|
&operation_id,
|
||||||
self_name,
|
self_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
let name = match name {
|
let name = match &operation_id {
|
||||||
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||||
|
::first_pass::OperationId::Operation(name) => match name {
|
||||||
None => {
|
None => {
|
||||||
warn!("Operations without a name are unsupported");
|
warn!("Operations without a name are unsupported");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(ref name) => name,
|
Some(name) => name.to_string(),
|
||||||
|
},
|
||||||
|
::first_pass::OperationId::IndexingGetter => "get".to_string(),
|
||||||
|
::first_pass::OperationId::IndexingSetter => "set".to_string(),
|
||||||
|
::first_pass::OperationId::IndexingDeleter => "delete".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
@ -935,7 +942,13 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
is_static,
|
is_static,
|
||||||
kind: backend::ast::OperationKind::Regular,
|
kind: match &operation_id {
|
||||||
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||||
|
::first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
||||||
|
::first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
||||||
|
::first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
||||||
|
::first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -951,7 +964,19 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let doc_comment = Some(format!("The `{}()` method\n\n{}", name, mdn_doc(self_name, Some(name))));
|
let doc_comment = match &operation_id {
|
||||||
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||||
|
::first_pass::OperationId::Operation(_) => Some(
|
||||||
|
format!(
|
||||||
|
"The `{}()` method\n\n{}",
|
||||||
|
name,
|
||||||
|
mdn_doc(self_name, Some(&name))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
::first_pass::OperationId::IndexingGetter => Some("The indexing getter\n\n".to_string()),
|
||||||
|
::first_pass::OperationId::IndexingSetter => Some("The indexing setter\n\n".to_string()),
|
||||||
|
::first_pass::OperationId::IndexingDeleter => Some("The indexing deleter\n\n".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
self.create_function(
|
self.create_function(
|
||||||
&name,
|
&name,
|
||||||
@ -960,11 +985,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
arguments,
|
arguments,
|
||||||
ret,
|
ret,
|
||||||
kind,
|
kind,
|
||||||
self
|
structural,
|
||||||
.interfaces
|
|
||||||
.get(self_name)
|
|
||||||
.map(|interface_data| interface_data.global)
|
|
||||||
.unwrap_or(false),
|
|
||||||
catch,
|
catch,
|
||||||
doc_comment,
|
doc_comment,
|
||||||
)
|
)
|
||||||
@ -975,14 +996,14 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
pub fn get_operation_overloading(
|
pub fn get_operation_overloading(
|
||||||
&self,
|
&self,
|
||||||
arguments: &[weedle::argument::Argument],
|
arguments: &[weedle::argument::Argument],
|
||||||
id: ::first_pass::OperationId,
|
id: &::first_pass::OperationId,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
) -> (bool, bool) {
|
) -> (bool, bool) {
|
||||||
let data = match self.interfaces.get(self_name) {
|
let data = match self.interfaces.get(self_name) {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return (false, false),
|
None => return (false, false),
|
||||||
};
|
};
|
||||||
let data = match data.operations.get(&id) {
|
let data = match data.operations.get(id) {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return (false, false),
|
None => return (false, false),
|
||||||
};
|
};
|
||||||
|
@ -126,7 +126,30 @@ possibilities!
|
|||||||
Properties in JS are accessed through `Object.getOwnPropertyDescriptor`. Note
|
Properties in JS are accessed through `Object.getOwnPropertyDescriptor`. Note
|
||||||
that this typically only works for class-like-defined properties which aren't
|
that this typically only works for class-like-defined properties which aren't
|
||||||
just attached properties on any old object. For accessing any old property on
|
just attached properties on any old object. For accessing any old property on
|
||||||
an object we can use...
|
an object we can use the `structural` flag.
|
||||||
|
|
||||||
|
* `indexing_getter`, `indexing_setter` and `indexing_deleter` - these three
|
||||||
|
attributes can be combined with `method` to indicate that this is a indexing
|
||||||
|
getter, indexing setter or indexing deleter method. They are different from
|
||||||
|
`getter` and `setter` in a way that `getter` and `setter` can only access
|
||||||
|
properties that have a name corresponding to the function name or their
|
||||||
|
argument, but `indexing_getter`, `indexing_setter` and `indexing_deleter`
|
||||||
|
work in a dynamic manner, similarly to the indexing syntax in JS
|
||||||
|
(`object[propertyName]`), hence the name. Should always be used together with
|
||||||
|
the `structural` flag. For example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern {
|
||||||
|
type Foo;
|
||||||
|
#[wasm_bindgen(method, structural, indexing_getter)]
|
||||||
|
fn get(this: &Foo, prop: &str) -> u32;
|
||||||
|
#[wasm_bindgen(method, structural, indexing_setter)]
|
||||||
|
fn set(this: &Foo, prop: &str, val: u32);
|
||||||
|
#[wasm_bindgen(method, structural, indexing_deleter)]
|
||||||
|
fn delete(this: &Foo, prop: &str);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* `structural` - this is a flag to `method` annotations which indicates that the
|
* `structural` - this is a flag to `method` annotations which indicates that the
|
||||||
method being accessed (or property with getters/setters) should be accessed in
|
method being accessed (or property with getters/setters) should be accessed in
|
||||||
|
Reference in New Issue
Block a user