wasm_streams/writable/
into_underlying_sink.rs1use std::cell::RefCell;
2use std::panic::AssertUnwindSafe;
3use std::pin::Pin;
4use std::rc::Rc;
5
6use futures_util::{Sink, SinkExt};
7use js_sys::Promise;
8use wasm_bindgen::prelude::*;
9use wasm_bindgen_futures::future_to_promise;
10
11#[wasm_bindgen]
12pub(crate) struct IntoUnderlyingSink {
13 inner: Rc<RefCell<Inner>>,
14}
15
16impl IntoUnderlyingSink {
17 pub fn new(sink: Box<dyn Sink<JsValue, Error = JsValue>>) -> Self {
18 IntoUnderlyingSink {
19 inner: Rc::new(RefCell::new(Inner::new(sink))),
20 }
21 }
22}
23
24#[allow(clippy::await_holding_refcell_ref)]
25#[wasm_bindgen]
26impl IntoUnderlyingSink {
27 pub fn write(&mut self, chunk: JsValue) -> Promise {
28 let inner = self.inner.clone();
29 future_to_promise(AssertUnwindSafe(async move {
34 let mut inner = inner.try_borrow_mut().unwrap_throw();
37 inner.write(chunk).await.map(|_| JsValue::undefined())
38 }))
39 }
40
41 pub fn close(self) -> Promise {
42 future_to_promise(AssertUnwindSafe(async move {
44 let mut inner = self.inner.try_borrow_mut().unwrap_throw();
45 inner.close().await.map(|_| JsValue::undefined())
46 }))
47 }
48
49 pub fn abort(self, reason: JsValue) -> Promise {
50 future_to_promise(AssertUnwindSafe(async move {
52 let mut inner = self.inner.try_borrow_mut().unwrap_throw();
53 inner.abort(reason).await.map(|_| JsValue::undefined())
54 }))
55 }
56}
57
58struct Inner {
59 sink: Option<Pin<Box<dyn Sink<JsValue, Error = JsValue>>>>,
60}
61
62impl Inner {
63 fn new(sink: Box<dyn Sink<JsValue, Error = JsValue>>) -> Self {
64 Inner {
65 sink: Some(sink.into()),
66 }
67 }
68
69 async fn write(&mut self, chunk: JsValue) -> Result<(), JsValue> {
70 let mut sink = self.sink.take().unwrap_throw();
74
75 match sink.send(chunk).await {
76 Ok(()) => {
77 self.sink = Some(sink);
79 Ok(())
80 }
81 Err(err) => {
82 Err(err)
84 }
85 }
86 }
88
89 async fn close(&mut self) -> Result<(), JsValue> {
90 self.sink.take().unwrap_throw().close().await
92 }
93
94 async fn abort(&mut self, _reason: JsValue) -> Result<(), JsValue> {
95 self.sink = None;
97 Ok(())
98 }
99}