【发布时间】:2022-01-01 15:43:54
【问题描述】:
我有一个现有的库,它通过引用具有生命周期参数的结构来公开必要的数据。问题是我需要使用wasm_bindgen 公开它。为此,我在我的 wasm 模块中创建了一个单独的结构:
#[wasm_bindgen]
struct Event {
// doesn't compile - passed from another lib
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
现在,问题在于 'a 和 'b 是从外部库传递的生命周期,但是 wasm-bindgen 的限制不允许即将通过 WebAssembly 访问的 Rust 结构包含任何泛型参数本身 - 因此Event 不能定义对'a 或'b 的任何引用。
虽然我可以通过使用原始指针来摆脱'a,但我不能对'b 做同样的事情。从技术上讲,我可以用'static 模拟它,但是我无法将结构的通用生命周期参数从'a 更改为'static。
如何以不与 wasm-bindgen 限制冲突的方式保持对 &'a InnerEvent<'b> 的引用?
编辑:
我的特定用例如下所示 - 我正在为库编写一个包装器,它为自定义用户数据启用 pub/sub:
pub struct Transaction<'txn> {
// .. omitted fields
}
pub struct SomeStruct {
pub fn subscribe<F>(&mut self, f: F) -> Subscription
where F: Fn(&Transaction, &Event) -> () + 'static {
// .. method body
}
}
现在我需要将 SomeStruct 暴露给 WebAssembly。为此,我正在创建一个 wasm-bingen 包装器,并且我需要它能够将其订阅功能暴露给 JavaScript 端:
#[wasm_bindgen]
pub struct SomeStructWrapper(SomeStruct);
#[wasm_bindgen]
impl SomeStructWrapper {
#[wasm_bindgen]
pub fn observe(&mut self, f: js_sys::Function) -> SubscriptionWrapper {
let sub = self.0.observe(move |transaction, event| {
// transaction is: &'a Transaction<'txn> and event: &'a Event
let e = EventWrapper::new(e, txn);
let arg: JsValue = e.into();
f.call1(&JsValue::UNDEFINED, &arg);
});
SubscriptionWrapper(sub)
}
}
#[wasm_bindgen]
pub struct SubscriptionWrapper(Subscription);
现在的问题是我需要在 JavaScript 回调中引用两个 rust 回调参数(事务和事件)。这意味着EventWrapper 需要将它们存储为字段:
// code below won't compile because
// wasm_bindgen doesn't allow its structs to declare lifecycle parameters
#[wasm_bindgen]
pub struct EventWrapper {
transaction: &'a Transaction<'txn>,
inner_event: &'a Event,
}
// we can get rid of 'a by casting references to raw pointers
// but this won't fix issue with 'txn lifecycle
#[wasm_bindgen]
pub struct EventWrapper {
transaction: *const Transaction<'txn>,
inner_event: *const Event,
}
【问题讨论】:
-
我建议在接触 wasm rust 之前学习 Rust,特别是因为 wasm rust 已经冻结了 > 1 年,并且最近才再次移动,你几乎找不到好的资源。
-
也许是一些非标准的用例,不确定是否忽略了一些东西,但 #[wasm_bindgen] 用于创建与 JavaScript 的粘合。如果现有的库是 Rust,它只是普通的接口还是?也许是一个最小的 repo,它说明了这个问题可以解释。
-
也许考虑包装例如与 Rc 的事务,可能与 Cell 或 RefCell 的额外事务,然后在构建 JavaScript 闭包时克隆,例如像这里github.com/rustwasm/wasm-bindgen/blob/main/examples/paint/src/… 这是在发送到 JavaScript 的闭包中处理静态生命周期要求的常见模式。
标签: rust wasm-bindgen