mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-12 04:21:21 +00:00
Support by-value self methods (#348)
Refactor slightly to use the same internal support that the other reference conversions are using. Closes #329
This commit is contained in:
@ -17,13 +17,19 @@ pub struct Program {
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
pub struct Export {
|
||||
pub class: Option<Ident>,
|
||||
pub method: bool,
|
||||
pub mutable: bool,
|
||||
pub method_self: Option<MethodSelf>,
|
||||
pub constructor: Option<String>,
|
||||
pub function: Function,
|
||||
pub comments: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
pub enum MethodSelf {
|
||||
ByValue,
|
||||
RefMutable,
|
||||
RefShared,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
pub struct Import {
|
||||
pub module: Option<String>,
|
||||
@ -170,8 +176,7 @@ impl Program {
|
||||
f.to_tokens(tokens);
|
||||
self.exports.push(Export {
|
||||
class: None,
|
||||
method: false,
|
||||
mutable: false,
|
||||
method_self: None,
|
||||
constructor: None,
|
||||
function: Function::from(f, opts),
|
||||
comments,
|
||||
@ -263,7 +268,7 @@ impl Program {
|
||||
None
|
||||
};
|
||||
|
||||
let (function, mutable) = Function::from_decl(
|
||||
let (function, method_self) = Function::from_decl(
|
||||
&method.sig.ident,
|
||||
Box::new(method.sig.decl.clone()),
|
||||
method.attrs.clone(),
|
||||
@ -274,8 +279,7 @@ impl Program {
|
||||
|
||||
self.exports.push(Export {
|
||||
class: Some(class.clone()),
|
||||
method: mutable.is_some(),
|
||||
mutable: mutable.unwrap_or(false),
|
||||
method_self,
|
||||
constructor,
|
||||
function,
|
||||
comments,
|
||||
@ -529,7 +533,7 @@ impl Function {
|
||||
opts: BindgenAttrs,
|
||||
vis: syn::Visibility,
|
||||
allow_self: bool,
|
||||
) -> (Function, Option<bool>) {
|
||||
) -> (Function, Option<MethodSelf>) {
|
||||
if decl.variadic.is_some() {
|
||||
panic!("can't bindgen variadic functions")
|
||||
}
|
||||
@ -541,17 +545,23 @@ impl Function {
|
||||
|
||||
let syn::FnDecl { inputs, output, .. } = { *decl };
|
||||
|
||||
let mut mutable = None;
|
||||
let mut method_self = None;
|
||||
let arguments = inputs
|
||||
.into_iter()
|
||||
.filter_map(|arg| match arg {
|
||||
syn::FnArg::Captured(c) => Some(c),
|
||||
syn::FnArg::SelfValue(_) => {
|
||||
panic!("by-value `self` not yet supported");
|
||||
assert!(method_self.is_none());
|
||||
method_self = Some(MethodSelf::ByValue);
|
||||
None
|
||||
}
|
||||
syn::FnArg::SelfRef(ref a) if allow_self => {
|
||||
assert!(mutable.is_none());
|
||||
mutable = Some(a.mutability.is_some());
|
||||
assert!(method_self.is_none());
|
||||
if a.mutability.is_some() {
|
||||
method_self = Some(MethodSelf::RefMutable);
|
||||
} else {
|
||||
method_self = Some(MethodSelf::RefShared);
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => panic!("arguments cannot be `self` or ignored"),
|
||||
@ -572,7 +582,7 @@ impl Function {
|
||||
rust_vis: vis,
|
||||
rust_attrs: attrs,
|
||||
},
|
||||
mutable,
|
||||
method_self,
|
||||
)
|
||||
}
|
||||
|
||||
@ -618,9 +628,15 @@ impl Export {
|
||||
}
|
||||
|
||||
fn shared(&self) -> shared::Export {
|
||||
let (method, consumed) = match self.method_self {
|
||||
Some(MethodSelf::ByValue) => (true, true),
|
||||
Some(_) => (true, false),
|
||||
None => (false, false),
|
||||
};
|
||||
shared::Export {
|
||||
class: self.class.as_ref().map(|s| s.to_string()),
|
||||
method: self.method,
|
||||
method,
|
||||
consumed,
|
||||
constructor: self.constructor.clone(),
|
||||
function: self.function.shared(),
|
||||
comments: self.comments.clone(),
|
||||
|
@ -309,16 +309,61 @@ impl ToTokens for ast::Export {
|
||||
let ret = Ident::new("_ret", Span::call_site());
|
||||
|
||||
let mut offset = 0;
|
||||
if self.method {
|
||||
let class = self.class.as_ref().unwrap();
|
||||
args.push(quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> });
|
||||
arg_conversions.push(quote! {
|
||||
::wasm_bindgen::__rt::assert_not_null(me);
|
||||
let me = unsafe { &*me };
|
||||
});
|
||||
if self.method_self.is_some() {
|
||||
args.push(quote! { me: u32 });
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
let name = &self.function.name;
|
||||
let receiver = match self.method_self {
|
||||
Some(ast::MethodSelf::ByValue) => {
|
||||
let class = self.class.as_ref().unwrap();
|
||||
arg_conversions.push(quote! {
|
||||
let me = unsafe {
|
||||
<#class as ::wasm_bindgen::convert::FromWasmAbi>::from_abi(
|
||||
me,
|
||||
&mut ::wasm_bindgen::convert::GlobalStack::new(),
|
||||
)
|
||||
};
|
||||
});
|
||||
quote! { me.#name }
|
||||
}
|
||||
Some(ast::MethodSelf::RefMutable) => {
|
||||
let class = self.class.as_ref().unwrap();
|
||||
arg_conversions.push(quote! {
|
||||
let mut me = unsafe {
|
||||
<#class as ::wasm_bindgen::convert::RefMutFromWasmAbi>
|
||||
::ref_mut_from_abi(
|
||||
me,
|
||||
&mut ::wasm_bindgen::convert::GlobalStack::new(),
|
||||
)
|
||||
};
|
||||
let me = &mut *me;
|
||||
});
|
||||
quote! { me.#name }
|
||||
}
|
||||
Some(ast::MethodSelf::RefShared) => {
|
||||
let class = self.class.as_ref().unwrap();
|
||||
arg_conversions.push(quote! {
|
||||
let me = unsafe {
|
||||
<#class as ::wasm_bindgen::convert::RefFromWasmAbi>
|
||||
::ref_from_abi(
|
||||
me,
|
||||
&mut ::wasm_bindgen::convert::GlobalStack::new(),
|
||||
)
|
||||
};
|
||||
let me = &*me;
|
||||
});
|
||||
quote! { me.#name }
|
||||
}
|
||||
None => {
|
||||
match &self.class {
|
||||
Some(class) => quote! { #class::#name },
|
||||
None => quote! { #name }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (i, syn::ArgCaptured { ty, .. }) in self.function.arguments.iter().enumerate() {
|
||||
let i = i + offset;
|
||||
let ident = Ident::new(&format!("arg{}", i), Span::call_site());
|
||||
@ -394,19 +439,6 @@ impl ToTokens for ast::Export {
|
||||
}
|
||||
None => quote! { inform(0); },
|
||||
};
|
||||
|
||||
let name = &self.function.name;
|
||||
let receiver = match &self.class {
|
||||
Some(_) if self.method => {
|
||||
if self.mutable {
|
||||
quote! { me.borrow_mut().#name }
|
||||
} else {
|
||||
quote! { me.borrow().#name }
|
||||
}
|
||||
}
|
||||
Some(class) => quote! { #class::#name },
|
||||
None => quote!{ #name },
|
||||
};
|
||||
let descriptor_name = format!("__wbindgen_describe_{}", export_name);
|
||||
let descriptor_name = Ident::new(&descriptor_name, Span::call_site());
|
||||
let nargs = self.function.arguments.len() as u32;
|
||||
|
Reference in New Issue
Block a user