Skip to main content

web_sys_async_io/
writer.rs

1use std::{
2    future::Future,
3    pin::Pin,
4    task::{ready, Poll},
5};
6
7use wasm_bindgen_futures::JsFuture;
8
9#[derive(Debug, Default)]
10pub enum Op {
11    #[default]
12    Idle,
13    Write(JsFuture, usize),
14    Flush(JsFuture),
15    Shutdown(JsFuture),
16}
17
18#[derive(Debug)]
19pub struct Writer {
20    pub inner: web_sys::WritableStreamDefaultWriter,
21    pub op: Op,
22}
23
24impl Writer {
25    pub fn new(inner: web_sys::WritableStreamDefaultWriter) -> Self {
26        Self {
27            inner,
28            op: Op::default(),
29        }
30    }
31}
32
33impl tokio::io::AsyncWrite for Writer {
34    fn poll_write(
35        mut self: std::pin::Pin<&mut Self>,
36        cx: &mut std::task::Context<'_>,
37        buf: &[u8],
38    ) -> std::task::Poll<Result<usize, std::io::Error>> {
39        match self.op {
40            Op::Write(ref mut fut, size) => {
41                let result = ready!(Pin::new(fut).poll(cx));
42                self.op = Op::Idle;
43                Poll::Ready(result.map(|_| size).map_err(super::js_value_to_io_error))
44            }
45            Op::Idle => {
46                let chunk = js_sys::Uint8Array::from(buf);
47                let fut = JsFuture::from(self.inner.write_with_chunk(chunk.as_ref()));
48                self.op = Op::Write(fut, buf.len());
49                self.poll_write(cx, buf)
50            }
51            _ => Poll::Pending,
52        }
53    }
54
55    fn poll_flush(
56        mut self: std::pin::Pin<&mut Self>,
57        cx: &mut std::task::Context<'_>,
58    ) -> std::task::Poll<Result<(), std::io::Error>> {
59        match self.op {
60            Op::Flush(ref mut fut) => {
61                let result = ready!(Pin::new(fut).poll(cx));
62                self.op = Op::Idle;
63                Poll::Ready(result.map(|_| ()).map_err(super::js_value_to_io_error))
64            }
65            Op::Idle => {
66                let fut = JsFuture::from(self.inner.ready());
67                self.op = Op::Flush(fut);
68                self.poll_flush(cx)
69            }
70            _ => Poll::Pending,
71        }
72    }
73
74    fn poll_shutdown(
75        mut self: std::pin::Pin<&mut Self>,
76        cx: &mut std::task::Context<'_>,
77    ) -> std::task::Poll<Result<(), std::io::Error>> {
78        match self.op {
79            Op::Shutdown(ref mut fut) => {
80                let result = ready!(Pin::new(fut).poll(cx));
81                self.op = Op::Idle;
82                Poll::Ready(result.map(|_| ()).map_err(super::js_value_to_io_error))
83            }
84            Op::Idle => {
85                let fut = JsFuture::from(self.inner.close());
86                self.op = Op::Shutdown(fut);
87                self.poll_shutdown(cx)
88            }
89            _ => Poll::Pending,
90        }
91    }
92}