Skip to content

Support for automatically clone()-ing objects to allow passing by value #4511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
richvdh opened this issue May 15, 2025 · 0 comments
Open

Comments

@richvdh
Copy link

richvdh commented May 15, 2025

Motivation

#1754 added support for #[wasm_bindgen] on async functions, which is great, because it generates a method on the Javascript side with a strong return type of Promise<Foo>.

However, as noted in that PR, it doesn't work correctly for methods that take &self, because that's not safe. [Aside: it seemed to compile fine for me, but it's certainly not safe and I ended up shooting my foot off. But I digress.]

The suggested workaround in #1754 is to use a wrapper type which contains an Rc<RefCell<InnerCore>> and pass that by value. This is fine, but you end up having to clone the wrapper on each call from Javascript. Something like this:

use std::{cell::RefCell, rc::Rc};
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
#[derive(Clone)]
pub struct Wrapper {
    inner: Rc<RefCell<InnerCore>>,
}

pub struct InnerCore {
    val: u32,
}

#[wasm_bindgen]
impl Wrapper {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        Self { inner: Rc::new(RefCell::new(InnerCore { val: 33 }))}
    }

    #[wasm_bindgen(js_name = "clone")]
    pub fn clone_me(&self) -> Self {
        self.clone()
    }

    #[wasm_bindgen(js_name = "getVal")]
    pub async fn get_val(self) -> u32 {
          self.inner.borrow().val
    }
}
import {Wrapper} from "./pkg/wasmtest.js";

const obj = new Wrapper();
console.log(await obj.clone().getVal());

This works fine, but requires the caller to remember to call clone(), otherwise they later get mysterious errors about "null pointer passed to rust", which is error-prone at best. It also means I need a shim for clone which I otherwise wouldn't need.

Proposed Solution

It would be really nice to be able to annotate the method to indicate that wasm-bindgen should generate glue code which clones the arguments. For example, maybe I could write something like the following to indicate that both arguments need cloning:

#[wasm_bindgen(js_name = "getVal", clone(self, arg0))]
pub async fn get_val(self: Wrapper, arg0: AnotherType) -> u32 {
    // ...
}

Alternatives

Additional Context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant