Skip to content
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

Should lifetimes on JS values be supported #423

Open
alexcrichton opened this issue Jul 8, 2018 · 3 comments
Open

Should lifetimes on JS values be supported #423

alexcrichton opened this issue Jul 8, 2018 · 3 comments

Comments

@alexcrichton
Copy link
Contributor

This first came up on #419, but one web API looks (sort of) like this:

#[wasm_bindgen]
extern {
    pub type ImageData;

    #[wasm_bindgen(constructor)]
    pub fn new(arr: &[u8], width: u32, height: u32) -> ImageData;
}

Here we're creating an ImageData while also passing a buffer of memory to its contructor. Presumably an ImageData retains a handle to the array passed in to later get rendered, which means that the lifetime of the ImageData instance produced is actually tied to the &[u8] passed in.

Normally in Rust this would be expressed through lifetimes, something like:

#[wasm_bindgen]
extern {
    pub type ImageData<'arr>;

    #[wasm_bindgen(constructor)]
    pub fn new(arr: &[u8], width: u32, height: u32) -> ImageData<'arr>;
}

but that's not supported by #[wasm_bindgen] today!

Should we somehow add support for these lifetimes? Or would this perhaps make web APIs too difficult to use? Should we instead leave-as is where you probably won't get a segfault but you'd get weird results sometimes?

@fitzgen
Copy link
Member

fitzgen commented Jul 9, 2018

I find that the most natural way to expose lifetimes to JS is to take a JS callback and say "the data passed to this callback may only be used while the call is active". This is not always super Rust-y, and not always applicable, but it is generally clear how to use the thing correctly from the JS side.

When JS owns something that borrows something else, it gets more difficult.

At the end of the day, FFI'ing with JS is always going to be unsafe, but our goal is to make the Rust side correct and easy. JS doesn't have borrowck, so lifetimes obviously can't improve the JS side, but they can improve the Rust side, and therefore are worthy of pursuit.

@khoover
Copy link

khoover commented Jul 2, 2021

I have a similar issue, this surrounding stack-lifetime callbacks inside of an options object. The problem there is, I have a class in JS like

class Foo {
  function totalCost(opts) { ... }
}

and inside the opts object is a cost function. What I'd like to do is be able to place a non-'static closure in the options object, something like

#[wasm_bindgen]
struct Options<'a> {
  cost_fn: &'a mut dyn FnMut(String) -> u32
}

but that fails to compile. In the meanwhile I've been using a helper module with a function that takes the partial options object and the callback as a parameter, puts the callback into the options, and calls totalCost, but I'd like to not exclude Node targets.

@daxpedda
Copy link
Collaborator

daxpedda commented Nov 7, 2024

I believe we should at least deprecate or potentially remove all these functions, as they are actually unsafe, until we find a proper solution.

Alternatives method signatures, by passing ArrayBuffers directly, where introduced in #4156.

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

No branches or pull requests

4 participants