WebAssembly:可以共享结构吗?

问题描述 投票:0回答:2

我想知道,使用 C(或 C++ 或 Rust)和 javascript,我是否能够对共享数据结构进行 CRUD 操作。使用最基本的示例,这里是每个操作的示例:

#include <stdio.h>
typedef struct Person {
    int age;
    char* name;
} Person;

int main(void) {

    // init
    Person* sharedPersons[100];
    int idx=0;

    // create
    sharedPersons[idx] = (Person*) {12, "Tom"};

    // read
    printf("{name: %s, age: %d}", sharedPersons[idx]->name, sharedPersons[idx]->age);

    // update
    sharedPersons[idx]->age = 11;

    // delete
    sharedPersons[idx] = NULL;

}

然后,我希望能够在 Javascript 中执行完全相同的操作,并且两者都能够写入相同的共享

sharedPersons
对象。这怎么可能做到呢?或者设置是否需要类似于“主从”,其中一个只需要将信息传递给另一个,而主站则执行所有相关操作?我希望有一种方法可以对 WebAssembly 中的共享数据对象进行 CRUD,并且我们将不胜感激任何帮助。

作为参考:https://rustwasm.github.io/wasm-bindgen/contributing/design/js-objects-in-rust.html

javascript c++ c rust webassembly
2个回答
6
投票

创建对象

让我们在 C 中创建对象并返回它:

typedef struct Person {
    int age;
    char* name;
} Person;

Person *get_persons(void) {
    Person* sharedPersons[100];
    return sharedPersons;
}

你也可以在JS中创建对象,但是比较难。我稍后会回来讨论这个问题。

为了让 JS 获取该对象,我们定义了一个返回(指向)该对象的函数(

get_persons
)。在本例中它是一个数组,但当然它也可以是单个对象。问题是,必须有一个从 JS 调用并提供对象的函数。

编译程序

emcc \
    -s "SINGLE_FILE=1" \
    -s "MODULARIZE=1" \
    -s "ALLOW_MEMORY_GROWTH=1" \
    -s "EXPORT_NAME=createModule" \
    -s "EXPORTED_FUNCTIONS=['_get_persons', '_malloc', '_free']" \
    -s "EXPORTED_RUNTIME_METHODS=['cwrap', 'setValue', 'getValue', 'AsciiToString', 'writeStringToMemory']" \
    -o myclib.js
    person.c

我不记得为什么我们在

_get_persons
中有一个前导下划线,但这就是 Emscripten 的工作原理。

在JS中获取对象

const createModule = require('./myclib');

let myclib;
let Module;

export const myclibRuntime = createModule().then((module) => {
  get_persons: Module.cwrap('get_persons', 'number', []),
});

它的作用是创建一个

get_persons()
JS 函数,它是 C
get_persons()
函数的包装器。 JS函数的返回值为“number”。 Emscripten 知道 C
get_persons()
函数返回一个指针,包装器会将该指针转换为 JS 数字。 (WASM 中的指针是 32 位的。)

在JS中操作对象

const persons = get_persons();
Module.getValue(persons, 'i32');  // Returns the age of the first person
Module.AsciiToString(Module.getValue(persons + 4, 'i32'));  // Name of first person

// Set the second person to be "Alice", age 18
const second_person = persons + 8;
Module.setValue(second_person, 18, 'i32');
const buffer = Module._malloc(6);  // Length of "Alice" plus the null terminator
Module.writeStringToMemory("Alice", buffer);
Module.setValue(second_person + 4, buffer, 'i32');

这是一种相当低级的方法,尽管似乎还有更低级的方法。正如其他人所建议的,可能有更高级别的工具可以帮助 C++ 和 Rust。

在JS中创建对象

您可以使用

_malloc()
在 JS 中创建对象(并使用
_free()
释放它们),就像我们对上面的字符串所做的那样,然后将它们的指针传递给 C 函数。但是,正如我所说,用 C 创建它们可能更容易。无论如何,任何
_malloc()
ed 的东西最终都必须被释放(因此上面的字符串创建是不完整的)。 FinalizationRegistry 可以帮助解决这个问题。


2
投票

是的,这是可能的。

WebAssembly 将对象存储在线性内存中,这是模块可以读取和写入的连续字节数组。主机环境(通常是 Web 浏览器中的 JavaScript)还可以读取和写入线性内存,从而允许它访问 WebAssembly 模块存储在那里的对象。

这里有两个挑战:

  1. 如何找到 WebAssembly 模块存储对象的位置?
  2. 对象是如何编码的?

您需要确保可以从 WebAssembly 模块和 JavaScript 主机读取和写入这些对象。

我会选择一个已知的内存位置和一个已知的序列化格式,并使用它从两侧读取/写入。

© www.soinside.com 2019 - 2024. All rights reserved.