如何将对象数组传递给 WebAssembly 并使用 wasm-bindgen 将其转换为结构向量?
How to pass an array of objects to WebAssembly and convert it to a vector of structs with wasm-bindgen?
可以像这样传递一个整数数组:
const js = import("./webassembly_rust");
let array_nums = [1,2,3,4,5,6,7,8,9];
js.then(js => {
js.test( array_nums );
});
到 WebAssembly 并将其保存在这样的向量中:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[wasm_bindgen]
pub fn test(array: JsValue) {
let elements: Vec<u32> = array.into_serde().unwrap();
}
也可以像这样传递单个对象:
const js = import("./webassembly_rust");
let jsObject = {name: "hello world", id: "99", parent_id: "11"};
js.then(js => {
js.test( jsObject );
});
到 WebAssembly 并将其保存为 Element
结构,如下所示:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_object: &JsValue) {
let element: Element = js_object.into_serde().unwrap();
}
接下来我尝试传递一个对象数组,如下所示:
const js = import("./webassembly_rust");
let arrayOfObjects = [
{name: "hello world", id: "99", parent_id: "88"},
{name: "hello world2", id: "88", parent_id: "12"},
{name: "hello world3", id: "77", parent_id: "88"}
]
js.then(js => {
js.test( arrayOfObjects );
});
到 WebAssembly 并将其保存为 Element
结构的向量,如下所示:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
}
这可以编译,但是当我 运行 这段代码时,我得到错误:
func $__rust_start_panic (param i32) (result i32)
unreachable
unreachable
end
像这样传递一个填充有数字的对象数组:
const js = import("./webassembly_rust");
let arrayOfNumObjects = [
{name: 1, id: 2, parent_id: 3 },
{name: 1, id: 2, parent_id: 3 },
{name: 1, id: 2, parent_id: 3 }
]
js.then(js => {
js.test( arrayOfNumObjects );
});
当 Element
结构仅包含 u32
个值时, 到 WebAssembly 是可能的。
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: u32,
id: u32,
parent_id: u32,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
}
问题似乎是由 Element
结构中的 String
类型引起的。
我做错了什么?
我找到了以下文章,但找不到解决我的问题的方法:
Serializing and Deserializing Arbitrary Data Into and From JsValue
with Serde
这说明了如何将 JavaScript 对象转换为结构,但没有说明如何将对象数组转换为结构向量。
-
这个 crate 允许在 Rust 中使用 JavaScript 类型,如数组或对象,但这不是我想要的。我想将 JavaScript 值转换成对应的 Rust 值。据我所知,这个箱子只允许在 Rust 中使用 JavaScript 内联......而且这不如只使用 Rust 快。
按照说明获取basic Rust / WASM setup, then add support for arbitrary data via Serde。
我已将您的代码更改为 return 一个数字并打印出该数字,只是为了看看它是否有效。
Cargo.toml
[package]
name = "ww"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
serde_json = "1.0.32"
serde_derive = "1.0.80"
serde = "1.0.80"
src/lib.rs
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) -> i32 {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
elements
.iter()
.map(|e| {
let id = e.id.parse::<i32>().unwrap_or(0);
let parent_id = e.parent_id.parse::<i32>().unwrap_or(0);
id + parent_id
})
.sum()
}
index.js
const js = import("./ww");
let arrayOfObjects = [
{ name: "hello world", id: "99", parent_id: "88" },
{ name: "hello world2", id: "88", parent_id: "12" },
{ name: "hello world3", id: "77", parent_id: "88" },
]
js.then(js => {
const sum = js.test(arrayOfObjects);
console.log(sum);
});
package.json
{
"scripts": {
"serve": "webpack-dev-server"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.0.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.0"
}
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
plugins: [
new HtmlWebpackPlugin({
title: "Getting started with WASM"
})
],
mode: "development"
};
然后运行:
# once
npm install
# every time the code changes
cargo +nightly build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/debug/*.wasm --out-dir .
npm run serve
在支持 WASM 的浏览器中访问页面。
细心的读者会注意到,我没有做任何与 OP 不同的事情。那是因为这段代码已经按原样工作了。每次更改 Rust 代码时,请确保:
- 构建你的 Rust 代码
- Re-运行 wasm-bindgen
可以像这样传递一个整数数组:
const js = import("./webassembly_rust");
let array_nums = [1,2,3,4,5,6,7,8,9];
js.then(js => {
js.test( array_nums );
});
到 WebAssembly 并将其保存在这样的向量中:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[wasm_bindgen]
pub fn test(array: JsValue) {
let elements: Vec<u32> = array.into_serde().unwrap();
}
也可以像这样传递单个对象:
const js = import("./webassembly_rust");
let jsObject = {name: "hello world", id: "99", parent_id: "11"};
js.then(js => {
js.test( jsObject );
});
到 WebAssembly 并将其保存为 Element
结构,如下所示:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_object: &JsValue) {
let element: Element = js_object.into_serde().unwrap();
}
接下来我尝试传递一个对象数组,如下所示:
const js = import("./webassembly_rust");
let arrayOfObjects = [
{name: "hello world", id: "99", parent_id: "88"},
{name: "hello world2", id: "88", parent_id: "12"},
{name: "hello world3", id: "77", parent_id: "88"}
]
js.then(js => {
js.test( arrayOfObjects );
});
到 WebAssembly 并将其保存为 Element
结构的向量,如下所示:
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
}
这可以编译,但是当我 运行 这段代码时,我得到错误:
func $__rust_start_panic (param i32) (result i32)
unreachable
unreachable
end
像这样传递一个填充有数字的对象数组:
const js = import("./webassembly_rust");
let arrayOfNumObjects = [
{name: 1, id: 2, parent_id: 3 },
{name: 1, id: 2, parent_id: 3 },
{name: 1, id: 2, parent_id: 3 }
]
js.then(js => {
js.test( arrayOfNumObjects );
});
当 Element
结构仅包含 u32
个值时,到 WebAssembly 是可能的。
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: u32,
id: u32,
parent_id: u32,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
}
问题似乎是由 Element
结构中的 String
类型引起的。
我做错了什么?
我找到了以下文章,但找不到解决我的问题的方法:
Serializing and Deserializing Arbitrary Data Into and From
JsValue
with Serde这说明了如何将 JavaScript 对象转换为结构,但没有说明如何将对象数组转换为结构向量。
-
这个 crate 允许在 Rust 中使用 JavaScript 类型,如数组或对象,但这不是我想要的。我想将 JavaScript 值转换成对应的 Rust 值。据我所知,这个箱子只允许在 Rust 中使用 JavaScript 内联......而且这不如只使用 Rust 快。
按照说明获取basic Rust / WASM setup, then add support for arbitrary data via Serde。
我已将您的代码更改为 return 一个数字并打印出该数字,只是为了看看它是否有效。
Cargo.toml
[package]
name = "ww"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
serde_json = "1.0.32"
serde_derive = "1.0.80"
serde = "1.0.80"
src/lib.rs
extern crate serde_json;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize)]
pub struct Element {
name: String,
id: String,
parent_id: String,
}
#[wasm_bindgen]
pub fn test(js_objects: &JsValue) -> i32 {
let elements: Vec<Element> = js_objects.into_serde().unwrap();
elements
.iter()
.map(|e| {
let id = e.id.parse::<i32>().unwrap_or(0);
let parent_id = e.parent_id.parse::<i32>().unwrap_or(0);
id + parent_id
})
.sum()
}
index.js
const js = import("./ww");
let arrayOfObjects = [
{ name: "hello world", id: "99", parent_id: "88" },
{ name: "hello world2", id: "88", parent_id: "12" },
{ name: "hello world3", id: "77", parent_id: "88" },
]
js.then(js => {
const sum = js.test(arrayOfObjects);
console.log(sum);
});
package.json
{
"scripts": {
"serve": "webpack-dev-server"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.0.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.0"
}
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
plugins: [
new HtmlWebpackPlugin({
title: "Getting started with WASM"
})
],
mode: "development"
};
然后运行:
# once
npm install
# every time the code changes
cargo +nightly build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/debug/*.wasm --out-dir .
npm run serve
在支持 WASM 的浏览器中访问页面。
细心的读者会注意到,我没有做任何与 OP 不同的事情。那是因为这段代码已经按原样工作了。每次更改 Rust 代码时,请确保:
- 构建你的 Rust 代码
- Re-运行 wasm-bindgen