Browse Source

LibWeb: Implement ReadableStream.pipeThrough()

Kenneth Myhra 1 year ago
parent
commit
d593436b6d

+ 23 - 0
Userland/Libraries/LibWeb/Streams/ReadableStream.cpp

@@ -110,6 +110,29 @@ WebIDL::ExceptionOr<ReadableStreamReader> ReadableStream::get_reader(ReadableStr
     return ReadableStreamReader { TRY(acquire_readable_stream_byob_reader(*this)) };
 }
 
+WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> ReadableStream::pipe_through(ReadableWritablePair transform, StreamPipeOptions const& options)
+{
+    // 1. If ! IsReadableStreamLocked(this) is true, throw a TypeError exception.
+    if (is_readable_stream_locked(*this))
+        return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Failed to execute 'pipeThrough' on 'ReadableStream': Cannot pipe a locked stream"sv };
+
+    // 2. If ! IsWritableStreamLocked(transform["writable"]) is true, throw a TypeError exception.
+    if (is_writable_stream_locked(*transform.writable))
+        return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Failed to execute 'pipeThrough' on 'ReadableStream': parameter 1's 'writable' is locked"sv };
+
+    // 3. Let signal be options["signal"] if it exists, or undefined otherwise.
+    auto signal = options.signal.has_value() ? JS::Value(options.signal.value().ptr()) : JS::js_undefined();
+
+    // 4. Let promise be ! ReadableStreamPipeTo(this, transform["writable"], options["preventClose"], options["preventAbort"], options["preventCancel"], signal).
+    auto promise = MUST(readable_stream_pipe_to(*this, *transform.writable, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal));
+
+    // 5. Set promise.[[PromiseIsHandled]] to true.
+    WebIDL::mark_promise_as_handled(*promise);
+
+    // 6. Return transform["readable"].
+    return JS::NonnullGCPtr { *transform.readable };
+}
+
 WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Object>> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options)
 {
     auto& realm = this->realm();

+ 6 - 0
Userland/Libraries/LibWeb/Streams/ReadableStream.h

@@ -27,6 +27,11 @@ struct ReadableStreamGetReaderOptions {
     Optional<Bindings::ReadableStreamReaderMode> mode;
 };
 
+struct ReadableWritablePair {
+    JS::GCPtr<ReadableStream> readable;
+    JS::GCPtr<WritableStream> writable;
+};
+
 struct StreamPipeOptions {
     bool prevent_close { false };
     bool prevent_abort { false };
@@ -70,6 +75,7 @@ public:
     bool locked() const;
     WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> cancel(JS::Value reason);
     WebIDL::ExceptionOr<ReadableStreamReader> get_reader(ReadableStreamGetReaderOptions const& = {});
+    WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {});
     WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Object>> pipe_to(WritableStream& destination, StreamPipeOptions const& = {});
     WebIDL::ExceptionOr<ReadableStreamPair> tee();
 

+ 6 - 1
Userland/Libraries/LibWeb/Streams/ReadableStream.idl

@@ -4,6 +4,11 @@
 #import <Streams/ReadableStreamDefaultReader.idl>
 #import <Streams/WritableStream.idl>
 
+dictionary ReadableWritablePair {
+  required ReadableStream readable;
+  required WritableStream writable;
+};
+
 dictionary StreamPipeOptions {
     boolean preventClose = false;
     boolean preventAbort = false;
@@ -30,7 +35,7 @@ interface ReadableStream {
 
     Promise<undefined> cancel(optional any reason);
     ReadableStreamReader getReader(optional ReadableStreamGetReaderOptions options = {});
-    // FIXME: ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {});
+    ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {});
     Promise<undefined> pipeTo(WritableStream destination, optional StreamPipeOptions options = {});
     sequence<ReadableStream> tee();