是否有可能在另一个 crate 中定义 #[wasm_bindgen] 公共结构体和函数?

10
我有一个装满结构体和实现的lib箱子。然后我有另一个名为web的箱子,将核心lib可移植到Web上。还有一个api,以防我想要应用程序是服务器端的。
  • myproject-api
  • myproject-lib
  • myproject-web
我不想在lib中添加所有wasm依赖项,只想在web项目中添加,并将主库中的部分内容暴露给Web。是否可以在myproject-web#[wasm_bindgen]定义myproject-lib中的结构体?

据我所知:没有。但是有一个选项可以不总是将结构体 #[wasm_bindgen],使用 Rust 的条件编译features 来只在依赖于 lib 的 crate 需要时才 #[wasm_bindgen] - MindSwipe
1个回答

12

不能直接实现。 #[wasm_bindgen] 属性依赖于能够解析结构体和 impls 以生成绑定。您需要创建包装类型和函数,供属性进行绑定。

假设您的 myproject-lib 如下:

pub struct MyStruct {
    pub foo: i32,
}

impl MyStruct {
    pub fn bar(&self) {
        // do something
    }
}

绑定将在myproject-web中实现,例如:
use myproject_lib::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(js_name = MyStruct)]
pub struct MyStructWrapper(MyStruct);

#[wasm_bindgen(js_class = MyStruct)]
impl MyStructWrapper {
    #[wasm_bindgen(getter)]
    pub fn foo(&self) -> i32 {
        self.0.foo
    }

    #[wasm_bindgen(setter)]
    pub fn set_foo(&mut self, value: i32) {
        self.0.foo = value;
    }

    pub fn bar(&self) {
        self.0.bar();
    }
}

正如您所看到的一样,所有工作都是非常明确地完成的。


我相信更广泛使用的方法是将绑定添加到原始库中,但仅在启用功能时才启用。这避免了很多重复工作,实现起来更加轻松,并确保绑定始终保持同步。

Cargo.toml中添加一个名为"wasm"特性,将wasm-bindgen作为可选择的依赖项添加进去:

[features]
wasm = ["wasm-bindgen"]

[dependencies]
wasm-bindgen = { version = "X.X.X", optional = true }

然后您可以使用 cfgcfg_attr,仅在启用该功能时才启用wasm_bindgen属性:

#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct MyStruct {
    pub foo: i32,
}

#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl MyStruct {
    pub fn bar(&self) {
        // do something
    }
}

1
哇哦,伙计,我已经创建了2或3个使用wasm实现的库,作为独立的库,直到我决定重新考虑这种方式。谢天谢地,我找到了你提供的带有特色依赖项的答案,这一直是正确的做法,而我像个傻瓜一样错过了它。 再次感谢你。 - Dominux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接