wasm-bindgen icon indicating copy to clipboard operation
wasm-bindgen copied to clipboard

Not sound to use lifetimes in function signatures

Open attente opened this issue 6 years ago • 12 comments

Seems like wasm-bindgen prohibits the use of lifetime specifiers in certain places where the compiler requires them. I have a test repo here: https://github.com/attente/wasm-bindgen-lifetime-issue

Building it, the error is:

[nix-shell:~/wasm-bindgen-lifetime-issue]$ cargo build --release --target=wasm32-unknown-unknown
   Compiling wasm-bindgen-lifetime-issue v0.1.0 (/home/william/wasm-bindgen-lifetime-issue)
error: it is currently not sound to use lifetimes in function signatures
  --> src/lib.rs:10:31
   |
10 |     pub fn f() -> Result<(), &'static str> {
   |                               ^^^^^^^

error: aborting due to previous error

error: Could not compile `wasm-bindgen-lifetime-issue`.

To learn more, run the command again with --verbose.

Unfortunately if I remove the 'static lifetime specifier, then the compiler will complain:

[nix-shell:~/wasm-bindgen-lifetime-issue]$ cargo build --release --target=wasm32-unknown-unknown
   Compiling wasm-bindgen-lifetime-issue v0.1.0 (/home/william/wasm-bindgen-lifetime-issue)
error[E0106]: missing lifetime specifier
  --> src/lib.rs:10:30
   |
10 |     pub fn f() -> Result<(), &str> {
   |                              ^ help: consider giving it a 'static lifetime: `&'static`
   |
   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from

error: aborting due to previous error

For more information about this error, try `rustc --explain E0106`.
error: Could not compile `wasm-bindgen-lifetime-issue`.

To learn more, run the command again with --verbose.

Is there any workaround for this issue?

attente avatar Jan 16 '19 20:01 attente

Thanks for the report! This is one I don't think we've given a ton of thought to just yet, but I suspect that with some work we could get 'static working as it doesn't run into the same issues as an arbitrary 'a. Would a String work for you use case for now though?

alexcrichton avatar Jan 17 '19 17:01 alexcrichton

Thanks for the feedback! What I ended up doing instead is changing my Error type from &'static str to i32, with numeric error codes. I'm sure it must be non-trivial to add lifetime support to wasm-bindgen.

attente avatar Jan 17 '19 20:01 attente

@attente i am agree this. when i learn rust, the rust-book tell me how important about the lifetime. so i learned the lifetime . but when i use rust to write a WebAssembly program, wasm-bindgen tell me i cant do this. Am i wrong? 😭

takkuumi avatar May 13 '19 15:05 takkuumi

The same issue I encountered. I suspect that wasm-bindgen do not support static lifetime yet either.

anymost avatar Jun 29 '19 16:06 anymost

So, I want to know When this bug will be fixed. Thanks a lot.

anymost avatar Jul 07 '19 08:07 anymost

same probleme here, I'm passing a js cloure to wasm, the complier tells me to add 'static lifetime parameter to the rust function signature, but wasm-bindgen forbids it.

oHaiyang avatar Aug 06 '19 05:08 oHaiyang

@oHaiyang did you find any solution or workaround for the closure problem?

chriamue avatar May 09 '21 19:05 chriamue

I'm also bit by this as I have data structures that have a lifetime on them. Even though I can support a static lifetime, I can't actually return them. An example (untested) of the issue I'm encountering:

#[wasm_bindgen]
#[derive(Serialize, Deserialize)]
pub struct SomeStruct<'a> { ... }

#[wasm_bindgen]
pub fn get_some_struct() -> SomeStruct<'static> {
    // Make a static instance
    SomeStruct { ... }
}

I can get around this by providing a wrapper type that contains the static instance, although I still have to convert to a JsValue to export.


#[wasm_bindgen]
pub struct Output(Page<'static>);

#[derive(Serialize, Deserialize)]
pub struct SomeStruct<'a> { ... }

#[wasm_bindgen]
impl Output {
    pub fn to_js(&self) -> JsValue {
        JsValue::from_serde(&self.0).unwrap()
    }
}

chipsenkbeil avatar May 18 '21 04:05 chipsenkbeil

+1 for this feature, thanks!

andreamancuso avatar May 22 '24 19:05 andreamancuso

Not ideal but this, after several hours of googling, trial/error, etc. (sadly not everyone is a Rust expert) is what I came up with:

image

image

image

image

image

andreamancuso avatar May 23 '24 12:05 andreamancuso

I'm also struggling with this. I have a parser that outputs a Token<'a> were the lifetime 'a is binded to the input &'a str

kind of like:

pub fn parse<'a>(input: &'a str) -> Result<Vec<Token<'a>>, ParseError> {}

any idea how can I create a wasbindgen for this case?

thanks!

woile avatar May 25 '24 06:05 woile

I got the following to compile:

use js_sys::{Array, Function};

struct Token<'a> {
    value: &'a str
}

#[derive(Debug)]
struct ParseError {}

pub fn parse<'a>(input: &'a str) -> Result<Vec<Token<'a>>, ParseError> {
    return Ok(Vec::<Token<'a>>::new());
}

#[wasm_bindgen]
pub fn parse_bindgen(input: JsValue) -> Array {
    let input_as_string = input.as_string().unwrap();
    let result = parse(input_as_string.as_str());
    let token_vector = result.unwrap();
    let array_length = token_vector.len() as u32;

    let arr = Array::new_with_length(array_length);
    for (i, token) in token_vector.iter().enumerate() {
        let s = JsValue::from("token?"); // replace with `Token`, though I don't know what it looks like
        arr.set(i as u32, s);
    }

    return arr;
}

You should take the above with several pinches of salt:

  • I am new to Rust
  • I made assumptions about Token
  • Based on the point above, I am not sure whether you would be able to run JsValue::from(), you might need to perform an intermediate conversion into a type of value that is actually supported

I hope this helps you. Feel free to let me know the outcome.

andreamancuso avatar May 25 '24 12:05 andreamancuso