Reputation: 3348
I have a problem where I need to return a tuple from a wasm function as the following:
#[wasm_bindgen]
pub fn channel() -> (futures::channel::mpsc::Sender<i32>, futures::channel::mpsc::Receiver<i32>) {
let (mut tx, mut rx) = futures::channel::mpsc::channel(32);
return (tx, rx)
}
(I need to return the sender and receiver with separate ownership)
It is not possible to return a tuple as explained here: https://stackoverflow.com/a/75064902/14923227
However, the provided workaround does not work for me since Receiver
does not implement Copy
or Clone
trait.
I have tried solving this by returning a Struct Pair
instead with getter methods for sender and receiver:
#[wasm_bindgen]
struct WrappedReceiver {
receiver: futures::channel::mpsc::Receiver<i32>
}
#[wasm_bindgen]
pub struct Pair {
sender: futures::channel::mpsc::Sender<i32>,
receiver: WrappedReceiver
}
#[wasm_bindgen]
impl Pair {
#[wasm_bindgen(getter)]
pub fn receiver(&self) -> WrappedReceiver {
return self.receiver
}
}
This compiles with the same issue, that WrappedReceiver does not implement Copy
trait.
I can however wrap the Receiver in Rc
with the following:
#[wasm_bindgen]
#[derive(Clone)]
pub struct WrappedSender(futures::channel::mpsc::Sender<i32>);
#[wasm_bindgen]
#[derive(Clone)]
pub struct WrappedReceiver(Rc<futures::channel::mpsc::Receiver<i32>>);
#[wasm_bindgen]
pub struct Pair {
#[wasm_bindgen(getter_with_clone)]
pub sender: WrappedSender,
#[wasm_bindgen(getter_with_clone)]
pub receiver: WrappedReceiver
}
#[wasm_bindgen]
impl Pair {
#[wasm_bindgen(constructor)]
pub fn new() -> Pair {
let (mut tx, mut rx) = futures::channel::mpsc::channel(32);
Pair {
sender: WrappedSender(tx),
receiver: WrappedReceiver(Rc::new(rx))
}
}
}
It not works to destruct the Pair in JavaScript with the following:
import * as wasm from './pkg'
const { receiver, sender } = new wasm.Pair()
I have some other place where I need to use the futures::channel::Receiver<i32>
with exclusive ownership &mut
(ideally I want it to be a futures stream).
#[wasm_bindgen]
pub fn use_receiever(receiver: &mut WrappedReceiver) {
let rx: Pin<Box<dyn futures::stream::Stream<Item = i32>>> = receiver.0.boxed_local();
}
This is because I cannot convert WrappedReceiver
to a &mut futures::channel::mpsc::Receiver<i32>
I think.
I could use a Rc<RefCell<futures::channel::mpsc::Receiver<i32>>>
which would allow me to borrow mutually:
#[wasm_bindgen]
pub fn use_receiever(receiver: &mut WrappedReceiver) {
let rx: &mut futures::channel::mpsc::Receiver<i32> = &mut receiver.0.borrow_mut();
}
This seems to work, but it feels like I am adding to many constructions. I also only want single ownership of futures::channel::mpsc::Receiver<i32>
, whereas RefCell is more suitable for multiple ownership?
Ideally I would like WrappedReceiver
to be the following:
#[wasm_bindgen]
struct WrappedReceiver {
receiver: Pin<Box<dyn futures::stream::Stream<Item = i32>>>,
}
Is there a way to achieve this?
Upvotes: 0
Views: 83
Reputation: 3348
It is possible to use Option
which has the take
method which moves the value out from the option. This makes it possible to temporarily take ownership of Receiver
.
#[wasm_bindgen]
pub struct Pair {
sender: futures::channel::mpsc::Sender<i32>,
receiver: Option<futures::channel::mpsc::Receiver<i32>>
}
#[wasm_bindgen]
impl Pair {
#[wasm_bindgen(constructor)]
pub fn new() -> Pair {
let (tx, rx) = futures::channel::mpsc::channel(32);
Pair {
sender: tx,
receiver: Some(rx)
}
}
#[wasm_bindgen(getter)]
pub fn receiver(&mut self) -> WrappedReceiver {
WrappedReceiver { receiver: self.receiver.take().unwrap().boxed_local() }
}
#[wasm_bindgen(getter)]
pub fn sender(&self) -> WrappedSender {
WrappedSender { sender: self.sender.clone() }
}
}
It is then possible to de-structure the object in JS with the following:
const { receiver, sender } = new wasm.Pair()
Upvotes: 0