web_sys_async_io/
writer.rs1use 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}