Bartosz Sypytkowski
Bartosz Sypytkowski

Reputation: 7542

Is it possible to change generic lifetime of a struct?

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

Answers (1)

Zeppi
Zeppi

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

Related Questions