From d8413774dfa71cf1ef8840735f8350dc274b34fc Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sun, 28 Jan 2024 10:28:59 -0500 Subject: [PATCH] LibWeb: Expose the ReadableStream `tee` IDL interface This just sets up the plumbing to the underlying ReadableStreamTee AO, which as of this commit, will just throw a NotImplemented exception. --- .../LibWeb/Streams/AbstractOperations.cpp | 15 +++++++++++++++ .../LibWeb/Streams/AbstractOperations.h | 2 ++ .../LibWeb/Streams/ReadableStream.cpp | 7 +++++++ .../Libraries/LibWeb/Streams/ReadableStream.h | 18 ++++++++++++++++++ .../LibWeb/Streams/ReadableStream.idl | 2 +- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp index e8f21782f6..38d5e96954 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -238,6 +238,21 @@ bool readable_stream_has_default_reader(ReadableStream const& stream) return false; } +// https://streams.spec.whatwg.org/#readable-stream-tee +WebIDL::ExceptionOr readable_stream_tee(JS::Realm& realm, ReadableStream& stream, bool) +{ + // 1. Assert: stream implements ReadableStream. + // 2. Assert: cloneForBranch2 is a boolean. + + // 3. If stream.[[controller]] implements ReadableByteStreamController, return ? ReadableByteStreamTee(stream). + if (stream.controller()->has>()) { + return realm.vm().throw_completion(JS::ErrorType::NotImplemented, "Byte stream teeing"); + } + + // 4. Return ? ReadableStreamDefaultTee(stream, cloneForBranch2). + return realm.vm().throw_completion(JS::ErrorType::NotImplemented, "Default stream teeing"); +} + // https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function JS::NonnullGCPtr extract_size_algorithm(JS::VM& vm, QueuingStrategy const& strategy) { diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h index 2a93eaad28..f24c0b1bb1 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h @@ -47,6 +47,8 @@ size_t readable_stream_get_num_read_requests(ReadableStream const&); bool readable_stream_has_byob_reader(ReadableStream const&); bool readable_stream_has_default_reader(ReadableStream const&); +WebIDL::ExceptionOr readable_stream_tee(JS::Realm&, ReadableStream&, bool clone_for_branch2); + WebIDL::ExceptionOr> readable_stream_reader_generic_cancel(ReadableStreamGenericReaderMixin&, JS::Value reason); void readable_stream_reader_generic_initialize(ReadableStreamReader, ReadableStream&); WebIDL::ExceptionOr readable_stream_reader_generic_release(ReadableStreamGenericReaderMixin&); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp index 761837c4f2..f4eb80abfe 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp @@ -108,6 +108,13 @@ WebIDL::ExceptionOr ReadableStream::get_reader(ReadableStr return ReadableStreamReader { TRY(acquire_readable_stream_byob_reader(*this)) }; } +// https://streams.spec.whatwg.org/#readablestream-tee +WebIDL::ExceptionOr ReadableStream::tee() +{ + // To tee a ReadableStream stream, return ? ReadableStreamTee(stream, true). + return TRY(readable_stream_tee(realm(), *this, true)); +} + void ReadableStream::initialize(JS::Realm& realm) { Base::initialize(realm); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.h b/Userland/Libraries/LibWeb/Streams/ReadableStream.h index b7deff5f86..e9459fb924 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.h @@ -26,6 +26,23 @@ struct ReadableStreamGetReaderOptions { Optional mode; }; +struct ReadableStreamPair { + // Define a couple container-like methods so this type may be used as the return type of the IDL `tee` implementation. + size_t size() const { return 2; } + + JS::NonnullGCPtr& at(size_t index) + { + if (index == 0) + return first; + if (index == 1) + return second; + VERIFY_NOT_REACHED(); + } + + JS::NonnullGCPtr first; + JS::NonnullGCPtr second; +}; + // https://streams.spec.whatwg.org/#readablestream class ReadableStream final : public Bindings::PlatformObject { WEB_PLATFORM_OBJECT(ReadableStream, Bindings::PlatformObject); @@ -45,6 +62,7 @@ public: bool locked() const; WebIDL::ExceptionOr> cancel(JS::Value reason); WebIDL::ExceptionOr get_reader(ReadableStreamGetReaderOptions const& = {}); + WebIDL::ExceptionOr tee(); Optional& controller() { return m_controller; } void set_controller(Optional value) { m_controller = move(value); } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.idl b/Userland/Libraries/LibWeb/Streams/ReadableStream.idl index 005ca11e0b..cedf67892d 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.idl +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.idl @@ -23,7 +23,7 @@ interface ReadableStream { ReadableStreamReader getReader(optional ReadableStreamGetReaderOptions options = {}); // FIXME: ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {}); // FIXME: Promise pipeTo(WritableStream destination, optional StreamPipeOptions options = {}); - // FIXME: sequence tee(); + sequence tee(); // FIXME: async iterable(optional ReadableStreamIteratorOptions options = {}); };