Skip to content

Commit

Permalink
Merge pull request #23 from MattiasBuelens/rs-from
Browse files Browse the repository at this point in the history
Add ReadableStream::from(async_iterable)
  • Loading branch information
MattiasBuelens authored Oct 31, 2023
2 parents 365fcc3 + 27ec304 commit 7809fc8
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Unreleased

* Added `ReadableStream::from(async_iterable)` and `try_from(async_iterable)`. ([#23](https://github.com/MattiasBuelens/wasm-streams/pull/23))
* Stop calling `byobRequest.respond(0)` on cancel ([#16](https://github.com/MattiasBuelens/wasm-streams/pull/16))
***Breaking change:** The system modules (`readable::sys`, `writable::sys` and `transform::sys`) now re-export directly from [the `web-sys` crate](https://docs.rs/web-sys/latest/web_sys/). This should make it easier to use `from_raw()`, `as_raw()` and `into_raw()`. ([#22](https://github.com/MattiasBuelens/wasm-streams/pull/22/))
***Breaking change:** The system modules (`readable::sys`, `writable::sys` and `transform::sys`) now re-export directly from [the `web-sys` crate](https://docs.rs/web-sys/latest/web_sys/). This should make it easier to use `from_raw()`, `as_raw()` and `into_raw()`. ([#22](https://github.com/MattiasBuelens/wasm-streams/pull/22))

## v0.3.0 (2022-10-16)

Expand Down
42 changes: 40 additions & 2 deletions src/readable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! [readable streams](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
use futures_util::io::AsyncRead;
use futures_util::Stream;
use js_sys::Object;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

Expand Down Expand Up @@ -72,7 +73,7 @@ impl ReadableStream {
let strategy = QueuingStrategy::new(0.0);
let raw = sys::ReadableStreamExt::new_with_into_underlying_source(source, strategy)
.unchecked_into();
Self { raw }
Self::from_raw(raw)
}

/// Creates a new `ReadableStream` from an [`AsyncRead`].
Expand All @@ -95,7 +96,44 @@ impl ReadableStream {
let raw = sys::ReadableStreamExt::new_with_into_underlying_byte_source(source)
.expect_throw("readable byte streams not supported")
.unchecked_into();
Self { raw }
Self::from_raw(raw)
}

/// Creates a new `ReadableStream` wrapping the provided [iterable] or [async iterable].
///
/// This can be used to adapt various kinds of objects into a readable stream,
/// such as an [array], an [async generator] or a [Node.js readable stream][Readable].
///
/// **Panics** if `ReadableStream.from()` is not supported by the browser,
/// or if the given object is not a valid iterable or async iterable.
/// For a non-panicking variant, use [`try_from`](Self::try_from).
///
/// [iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol
/// [async iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols
/// [array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
/// [async generator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator
/// [Readable]: https://nodejs.org/api/stream.html#class-streamreadable
pub fn from(async_iterable: Object) -> Self {
Self::try_from(async_iterable).unwrap_throw()
}

/// Try to create a new `ReadableStream` wrapping the provided [iterable] or [async iterable].
///
/// This can be used to adapt various kinds of objects into a readable stream,
/// such as an [array], an [async generator] or a [Node.js readable stream][Readable].
///
/// If `ReadableStream.from()` is not supported by the browser,
/// or if the given object is not a valid iterable or async iterable,
/// then this returns an error.
///
/// [iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol
/// [async iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols
/// [array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
/// [async generator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator
/// [Readable]: https://nodejs.org/api/stream.html#class-streamreadable
pub fn try_from(async_iterable: Object) -> Result<Self, js_sys::Error> {
let raw = sys::ReadableStreamExt::from_async_iterable(&async_iterable)?.unchecked_into();
Ok(Self::from_raw(raw))
}

/// Acquires a reference to the underlying [JavaScript stream](sys::ReadableStream).
Expand Down
3 changes: 3 additions & 0 deletions src/readable/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ extern "C" {

#[wasm_bindgen(method, catch, js_class = ReadableStream, js_name = tee)]
pub(crate) fn try_tee(this: &ReadableStreamExt) -> Result<Array, Error>;

#[wasm_bindgen(catch, static_method_of = ReadableStreamExt, js_class = ReadableStream, js_name = from)]
pub(crate) fn from_async_iterable(async_iterable: &Object) -> Result<ReadableStreamExt, Error>;
}

#[wasm_bindgen]
Expand Down
2 changes: 1 addition & 1 deletion src/writable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl WritableStream {
// Use the default queuing strategy (with a HWM of 1 chunk).
// We shouldn't set HWM to 0, since that would break piping to the writable stream.
let raw = sys::WritableStreamExt::new_with_into_underlying_sink(sink).unchecked_into();
WritableStream { raw }
Self::from_raw(raw)
}

/// Acquires a reference to the underlying [JavaScript stream](sys::WritableStream).
Expand Down
25 changes: 25 additions & 0 deletions tests/tests/readable_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,28 @@ async fn test_readable_stream_into_stream_then_into_async_read() {
assert_eq!(async_read.read(&mut buf).await.unwrap(), 0);
assert_eq!(&buf, &[4, 5, 6]);
}

#[wasm_bindgen_test]
async fn test_readable_stream_from_js_array() {
let js_array =
js_sys::Array::from_iter([JsValue::from_str("Hello"), JsValue::from_str("world!")]);
let mut readable = match ReadableStream::try_from(js_array.unchecked_into()) {
Ok(readable) => readable,
Err(err) => {
// ReadableStream.from() is not yet supported in all browsers.
assert_eq!(err.name(), "TypeError");
assert_eq!(
err.message().as_string().unwrap(),
"ReadableStream.from is not a function"
);
return;
}
};
assert!(!readable.is_locked());

let mut reader = readable.get_reader();
assert_eq!(reader.read().await.unwrap(), Some(JsValue::from("Hello")));
assert_eq!(reader.read().await.unwrap(), Some(JsValue::from("world!")));
assert_eq!(reader.read().await.unwrap(), None);
reader.closed().await.unwrap();
}

0 comments on commit 7809fc8

Please sign in to comment.