Wasm-bindgen: Vectors not working in structs

Created on 10 Jul 2018  路  10Comments  路  Source: rustwasm/wasm-bindgen

I'm receiving the following error:
the traitstd::marker::Copyis not implemented forstd::vec::Vec

for this struct:

#[wasm_bindgen]
pub struct Mesh{
    pub tris: Vec<u32>,
}

If I change tris' type to u32, the error goes away.

This page lists Vectors and slices of supported integer types as supported.

Most helpful comment

You also cannot store a pub String in a struct, presumably for the same reason outlined in this issue. Strings are pretty fundamental types. Could we expand the documentation to mention this limitation? https://rustwasm.github.io/docs/wasm-bindgen/reference/types/string.html

All 10 comments

Thanks for the report! Currently though public struct fields are a special case in that they only work with Copy types. This should definitely be better documented!

Thanks; removing pub on the field fixed it

Related Q: How do you extract a value from a struct passed via bindgen to JS? The object I see when printing to console.log() contains a ptr field of a large integer, and a very deep recursive structure containing values like , free, constructor, bind, call etc. Eg, how can I make mesh.tris work, eg returning a number[] ?

This page in the official guide shows example struct passing from Rust to JS, but doesn't show accessing a value contained in one.

edit: Getter functions, like in the example on that guide appear to work. Is there a way around this? Perhaps auto-generating getter funcs for all struct fields?

@David-OConnor ah that's got its own separate bug for defining JS getters in Rust

@alexcrichton Perhaps the solution, assuming there's an obstacle to exposing fields directly, is to serialize the struct, pass it to JS, then deserialize into an object. This assumes no methods.

Oh currently the main obstacle in a sense is that it's not clear what to do if the field isn't Copy because JS gets just a snapshot and mutating that isn't clear you're not mutating the original Rust value. For example in JS if you did mesh.tris.push(3) it wouldn't necessarily be reflected back in the tris field in Rust.

That makes sense. One way to handle this is to send one-way structs to JS, that don't call back to the Rust code. I got it working like this, using serde:

Rust:

#[derive(Serialize)]
#[wasm_bindgen]
pub struct MyStruct {
    // All fields here are are serializable by Serde, or are structs that derive Serialize themselves.
}

#[wasm_bindgen]
pub fn get_mystruct() -> String {
    let mystruct = MyStruct {..};

    serde_json::to_string(&mystruct).unwrap()
}

JS:

const rust = import("./from_rust");
rust.then(
    r =>
    {
        let myStruct = JSON.parse(get_mystruct());
    })

No methods, but can be fed into a constructor for a JS object that has methods, or just used as-is, optionally by declaring it with a Typescript interface.

@alexcrichton Do you think this would be useful in a more streamlined, official way, eg that handles the serialization/deserialization automatically? This seems like it could be a common use-case. Eg make Rust code that does something complicated or interesting, then call a Rust func from JS, which passes the result in whichever data structures are convenient... At least when I heard of WASM and bindgen, this was the first use-case that came to mind.

@alexcrichton Sick!

You also cannot store a pub String in a struct, presumably for the same reason outlined in this issue. Strings are pretty fundamental types. Could we expand the documentation to mention this limitation? https://rustwasm.github.io/docs/wasm-bindgen/reference/types/string.html

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bantic picture bantic  路  4Comments

MarcAntoine-Arnaud picture MarcAntoine-Arnaud  路  3Comments

poccariswet picture poccariswet  路  3Comments

kurbaniec picture kurbaniec  路  3Comments

NateLing picture NateLing  路  3Comments