Reputation: 7542
I have an existing library which exposes a necessary data via reference to a struct with lifetime parameter. The problem is that I need to expose it using wasm_bindgen
. For that I've created a separate struct in my wasm module:
#[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 }
}
}
Now, the problem is that 'a
and 'b
are lifetimes that are passed from an outer library, but wasm-bindgen limitations doesn't allow for a Rust struct that's about to be accessible via WebAssembly to contain any generic params on its own - therefore Event
cannot define any references to 'a
or 'b
.
While I can get rid of 'a
by using raw pointers, I cannot do the same with 'b
. Technically I can mock it with 'static
, however I'm unable to change struct's generic lifetime param from 'a
to 'static
.
How can I keep reference to an &'a InnerEvent<'b>
in a way that doesn't collide with wasm-bindgen restrictions?
EDIT:
My particular use case looks like follows - I'm writing a wrapper over a library, that enables a pub/sub for custom user data:
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
}
}
Now I need to expose SomeStruct
over to WebAssembly. For this I'm creating a wasm-bingen wrapper, and I need it to be able to expose its subscribe capabilities over to a JavaScript side:
#[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);
Now the problem is that I need to references to both of the rust callback parameters (transaction and event) inside of JavaScript callback. This means that EventWrapper
needs to store them as fields:
// 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,
}
Upvotes: 2
Views: 744
Reputation: 1235
In the below code, it get error `error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently?
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
#[wasm_bindgen]
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
Output
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
--> src\lib.rs:8:13
|
8 | struct Event<'a,'b> where 'a: 'b {
| ^^^^^^^
You can get around like that
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
#[wasm_bindgen]
struct WrapEvent
{
i: Event<'static, 'static>
}
But this meet your requierement?
This issue is also discussed here How to get rid of lifetime in wrapper struct for wasm_bindgen
Upvotes: 0