wasm_streams/writable/
default_writer.rs

1use std::marker::PhantomData;
2
3use wasm_bindgen::{throw_val, JsValue};
4
5use crate::util::promise_to_void_future;
6
7use super::{sys, IntoAsyncWrite, IntoSink, WritableStream};
8
9/// A [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)
10/// that can be used to write chunks to a [`WritableStream`](WritableStream).
11///
12/// This is returned by the [`get_writer`](WritableStream::get_writer) method.
13///
14/// When the writer is dropped, it automatically [releases its lock](https://streams.spec.whatwg.org/#release-a-lock).
15#[derive(Debug)]
16pub struct WritableStreamDefaultWriter<'stream> {
17    raw: sys::WritableStreamDefaultWriter,
18    _stream: PhantomData<&'stream mut WritableStream>,
19}
20
21impl<'stream> WritableStreamDefaultWriter<'stream> {
22    pub(crate) fn new(stream: &mut WritableStream) -> Result<Self, js_sys::Error> {
23        Ok(Self {
24            raw: stream.as_raw().get_writer()?,
25            _stream: PhantomData,
26        })
27    }
28
29    /// Acquires a reference to the underlying [JavaScript writer](sys::WritableStreamDefaultWriter).
30    #[inline]
31    pub fn as_raw(&self) -> &sys::WritableStreamDefaultWriter {
32        &self.raw
33    }
34
35    /// Waits for the stream to become closed.
36    ///
37    /// This returns an error if the stream ever errors, or if the writer's lock is
38    /// [released](https://streams.spec.whatwg.org/#release-a-lock) before the stream finishes
39    /// closing.
40    pub async fn closed(&self) -> Result<(), JsValue> {
41        promise_to_void_future(self.as_raw().closed()).await
42    }
43
44    /// Returns the desired size to fill the stream's internal queue.
45    ///
46    /// * It can be negative, if the queue is over-full.
47    ///   A producer can use this information to determine the right amount of data to write.
48    /// * It will be `None` if the stream cannot be successfully written to
49    ///   (due to either being errored, or having an abort queued up).
50    /// * It will return zero if the stream is closed.
51    #[inline]
52    pub fn desired_size(&self) -> Option<f64> {
53        self.as_raw()
54            .desired_size()
55            .unwrap_or_else(|error| throw_val(error))
56    }
57
58    /// Waits until the desired size to fill the stream's internal queue transitions
59    /// from non-positive to positive, signaling that it is no longer applying backpressure.
60    ///
61    /// Once the desired size to fill the stream's internal queue dips back to zero or below,
62    /// this will return a new future that stays pending until the next transition.
63    ///
64    /// This returns an error if the stream ever errors, or if the writer's lock is
65    /// [released](https://streams.spec.whatwg.org/#release-a-lock) before the stream finishes
66    /// closing.
67    pub async fn ready(&self) -> Result<(), JsValue> {
68        promise_to_void_future(self.as_raw().ready()).await
69    }
70
71    /// [Aborts](https://streams.spec.whatwg.org/#abort-a-writable-stream) the stream,
72    /// signaling that the producer can no longer successfully write to the stream.
73    ///
74    /// Equivalent to [`WritableStream.abort`](WritableStream::abort).
75    pub async fn abort(&mut self) -> Result<(), JsValue> {
76        promise_to_void_future(self.as_raw().abort()).await
77    }
78
79    /// [Aborts](https://streams.spec.whatwg.org/#abort-a-writable-stream) the stream with the
80    /// given `reason`, signaling that the producer can no longer successfully write to the stream.
81    ///
82    /// Equivalent to [`WritableStream.abort_with_reason`](WritableStream::abort_with_reason).
83    pub async fn abort_with_reason(&mut self, reason: &JsValue) -> Result<(), JsValue> {
84        promise_to_void_future(self.as_raw().abort_with_reason(reason)).await
85    }
86
87    /// Writes the given `chunk` to the writable stream, by waiting until any previous writes
88    /// have finished successfully, and then sending the chunk to the underlying sink's `write()`
89    /// method.
90    ///
91    /// This returns `Ok(())` upon a successful write, or `Err(error)` if the write fails or stream
92    /// becomes errored before the writing process is initiated.
93    ///
94    /// Note that what "success" means is up to the underlying sink; it might indicate simply
95    /// that the chunk has been accepted, and not necessarily that it is safely saved to
96    /// its ultimate destination.
97    pub async fn write(&mut self, chunk: JsValue) -> Result<(), JsValue> {
98        promise_to_void_future(self.as_raw().write_with_chunk(&chunk)).await
99    }
100
101    /// Closes the stream.
102    ///
103    /// The underlying sink will finish processing any previously-written chunks, before invoking
104    /// its close behavior. During this time any further attempts to write will fail
105    /// (without erroring the stream).
106    ///
107    /// This returns `Ok(())` if all remaining chunks are successfully written and the stream
108    /// successfully closes, or `Err(error)` if an error is encountered during this process.
109    pub async fn close(&mut self) -> Result<(), JsValue> {
110        promise_to_void_future(self.as_raw().close()).await
111    }
112
113    /// Converts this `WritableStreamDefaultWriter` into a [`Sink`].
114    ///
115    /// This is similar to [`WritableStream.into_sink`](WritableStream::into_sink),
116    /// except that after the returned `Sink` is dropped, the original `WritableStream` is still
117    /// usable. This allows writing only a few chunks through the `Sink`, while still allowing
118    /// another writer to write more chunks later on.
119    ///
120    /// [`Sink`]: https://docs.rs/futures/0.3.30/futures/sink/trait.Sink.html
121    #[inline]
122    pub fn into_sink(self) -> IntoSink<'stream> {
123        IntoSink::new(self)
124    }
125
126    /// Converts this `WritableStreamDefaultWriter` into an [`AsyncWrite`].
127    ///
128    /// The writable stream must accept [`Uint8Array`](js_sys::Uint8Array) chunks.
129    ///
130    /// This is similar to [`WritableStream.into_async_write`](WritableStream::into_async_write),
131    /// except that after the returned `AsyncWrite` is dropped, the original `WritableStream` is
132    /// still usable. This allows writing only a few bytes through the `AsyncWrite`, while still
133    /// allowing another writer to write more bytes later on.
134    ///
135    /// [`AsyncWrite`]: https://docs.rs/futures/0.3.30/futures/io/trait.AsyncWrite.html
136    #[inline]
137    pub fn into_async_write(self) -> IntoAsyncWrite<'stream> {
138        IntoAsyncWrite::new(self.into_sink())
139    }
140}
141
142impl Drop for WritableStreamDefaultWriter<'_> {
143    fn drop(&mut self) {
144        self.as_raw().release_lock()
145    }
146}