wasm-bindgen icon indicating copy to clipboard operation
wasm-bindgen copied to clipboard

Stream from AsyncIterator in wasm-bindgen-futures

Open olanod opened this issue 5 years ago • 3 comments

AsyncIterator in JS is the native equivalent of Promise to represent multiple future values instead of one just as in Rust we have Future and Stream(soon in the standard library). Instead of creating a separate utility crate that converts async iterators to Rust streams I propose having that in function(e.g. iter_to_stream) in the wasm-bindgen-futures crate since the feature(can be behind a flag) is very "futures" related.

olanod avatar Dec 19 '20 09:12 olanod

This would be awesome! Would it be possible to have the opposite too i.e. subscribe to a Rust Stream from Javascript via the registration of a callback/RxJS Observable or similar? Apologies in advance if this has an obvious solution, I am at the beginning of my journey with Rust...

I know already that you can call pre-existing global/static JS functions from Rust via an extern "C" block. However, it would be great to be able to manage subscriptions dynamically. I tried passing in a &js_sys::Function callback, but I couldn't get the callback to survive longer than the registration function:

use std::collections::HashMap;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
#[derive(Default)]
pub struct Subscribable<'a> { // compiler error that lifetimes aren't available 
  xs: Vec<u32>,
  subscribers: HashMap<u32, &'a js_sys::Function>,
  next_id: u32,
}

#[wasm_bindgen]
impl Subscribable {
  pub fn new() -> Self {
    Self {
      xs: vec![1, 2, 3],
      subscribers: HashMap::new(),
      next_id: 0,
    }
  }

  pub fn each(&self, callback: &js_sys::Function) {
    let this = JsValue::null();

    for &x in &self.xs {
      let x = JsValue::from(x);
      callback.call1(&this, &x);
    }
  }

  // subscriber can't survive past the end of this method
  pub fn subscribe(&mut self, subscriber: &js_sys::Function) -> u32 {
    let id = self.next_id;
    self.subscribers.insert(id, subscriber);
    self.next_id += 1;
    id
  }

  pub fn unsubscribe(&self, subscription: u32) {
    self.subscribers.remove(&subscription);
  }
}

Any pointers would be hugely appreciated!

mattgibb avatar Dec 29 '20 16:12 mattgibb

@mattgibb Hi! Did you ever figure out how to do this? I'm at the same point now, having streams in Rust that I want to react to in JS, without a separate global listener function import. Either with callbacks like your code above, or by converting to an AsyncIterator.

sisou avatar Feb 16 '23 22:02 sisou

@mattgibb你好!你有想过如何做到这一点吗?我现在处于同一点,在 Rust 中有流,我想在 JS 中做出反应,而不需要单独的全局侦听器函数导入。使用像上面的代码这样的回调,或者转换为 AsyncIterator。

+1

kitty-eu-org avatar Apr 16 '24 10:04 kitty-eu-org