mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-14 21:41:23 +00:00
Remove the need for a ConstructorToken
This commit removes the need for an injected `ConstructorToken` type and also cleans up the story we have for generating constructors a bit. After this commit a `constructor()` is omitted entirely if we're in non-debug mode and there's no actual listed constructor. Additionally we don't deal with splat arguments and rerouting constructors, Nick was kind enough to enlighten me about `Object.create` which is creating an instance without running the constructor! Instances of an exported type are now created through one of two methods: * If `#[wasm_bindgen(constructor)]` is present, then a `constructor` is generated with the appropriate signature. If a constructor is not present and we're in debug mode, a throwing constructor is generated. If we're in release mode and there's no constructor, no constructor is generated. * Otherwise if a binding returns an instance of a type (or otherwise needs to manfuacture an instance, then it will cause an internal `__wrap` function to be generated. This function will use `Object.create` to create an instance without running the constructor. This should ideally clean up our generated JS for classes quite a bit, making it much more lean-and-mean!
This commit is contained in:
@ -37,6 +37,14 @@ pub struct Js2Rust<'a, 'b: 'a> {
|
||||
/// Name of the JS shim/function that we're generating, primarily for
|
||||
/// TypeScript right now.
|
||||
js_name: String,
|
||||
|
||||
/// whether or not this generated function body will act like a constructor,
|
||||
/// meaning it doesn't actually return something but rather assigns to
|
||||
/// `this`
|
||||
///
|
||||
/// The string value here is the class that this should be a constructor
|
||||
/// for.
|
||||
constructor: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
@ -51,6 +59,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
arg_idx: 0,
|
||||
ret_ty: String::new(),
|
||||
ret_expr: String::new(),
|
||||
constructor: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,6 +73,11 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn constructor(&mut self, class: Option<&str>) -> &mut Self {
|
||||
self.constructor = class.map(|s| s.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Flag this shim as a method call into Rust, so the first Rust argument
|
||||
/// passed should be `this.ptr`.
|
||||
pub fn method(&mut self, method: bool, consumed: bool) -> &mut Self {
|
||||
@ -393,6 +407,32 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
}
|
||||
|
||||
pub fn ret(&mut self, ty: &Descriptor) -> Result<&mut Self, Error> {
|
||||
if let Some(name) = ty.rust_struct() {
|
||||
match &self.constructor {
|
||||
Some(class) if class == name => {
|
||||
self.ret_expr = format!("this.ptr = RET;");
|
||||
if self.cx.config.weak_refs {
|
||||
self.ret_expr.push_str(&format!("\
|
||||
addCleanup(this, this.ptr, free{});
|
||||
", name));
|
||||
}
|
||||
}
|
||||
Some(class) => {
|
||||
bail!("constructor for `{}` cannot return `{}`", class, name)
|
||||
}
|
||||
None => {
|
||||
self.ret_ty = name.to_string();
|
||||
self.cx.require_class_wrap(name);
|
||||
self.ret_expr = format!("return {name}.__wrap(RET);", name = name);
|
||||
}
|
||||
}
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
if self.constructor.is_some() {
|
||||
bail!("constructor functions must return a Rust structure")
|
||||
}
|
||||
|
||||
if let Descriptor::Unit = ty {
|
||||
self.ret_ty = "void".to_string();
|
||||
self.ret_expr = format!("return RET;");
|
||||
@ -551,7 +591,8 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
|
||||
if let Some(name) = ty.rust_struct() {
|
||||
self.ret_ty = name.to_string();
|
||||
self.ret_expr = format!("return {name}.__construct(RET);", name = name);
|
||||
self.cx.require_class_wrap(name);
|
||||
self.ret_expr = format!("return {name}.__wrap(RET);", name = name);
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user