From 1daded768d1d599502d11913a6bbaf5ea418a954 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Sun, 19 Nov 2023 12:44:42 +1300 Subject: [PATCH] LibWeb: Implement ReadableStreamBYOBReader::read Similiarly to the underlying AO's, currently only TypedArrays are supported. --- .../Streams/ReadableStreamBYOBReader-read.txt | 3 + .../ReadableStreamBYOBReader-read.html | 31 ++++++ .../Streams/ReadableStreamBYOBReader.cpp | 98 +++++++++++++++++++ .../LibWeb/Streams/ReadableStreamBYOBReader.h | 2 + .../Streams/ReadableStreamBYOBReader.idl | 5 +- 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 Tests/LibWeb/Text/expected/Streams/ReadableStreamBYOBReader-read.txt create mode 100644 Tests/LibWeb/Text/input/Streams/ReadableStreamBYOBReader-read.html diff --git a/Tests/LibWeb/Text/expected/Streams/ReadableStreamBYOBReader-read.txt b/Tests/LibWeb/Text/expected/Streams/ReadableStreamBYOBReader-read.txt new file mode 100644 index 0000000000..17d0a84eda --- /dev/null +++ b/Tests/LibWeb/Text/expected/Streams/ReadableStreamBYOBReader-read.txt @@ -0,0 +1,3 @@ +About to read! [object ReadableStreamBYOBReader] +Total bytes: 34 +'This is some data to be read! 🦬' diff --git a/Tests/LibWeb/Text/input/Streams/ReadableStreamBYOBReader-read.html b/Tests/LibWeb/Text/input/Streams/ReadableStreamBYOBReader-read.html new file mode 100644 index 0000000000..21ae02065f --- /dev/null +++ b/Tests/LibWeb/Text/input/Streams/ReadableStreamBYOBReader-read.html @@ -0,0 +1,31 @@ + + diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp index 6adbec5317..50d62771e2 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -56,4 +57,101 @@ void ReadableStreamBYOBReader::visit_edges(Cell::Visitor& visitor) visitor.visit(request); } +class BYOBReaderReadIntoRequest : public ReadIntoRequest { + JS_CELL(BYOBReaderReadIntoRequest, ReadIntoRequest); + +public: + BYOBReaderReadIntoRequest(JS::Realm& realm, WebIDL::Promise& promise) + : m_realm(realm) + , m_promise(promise) + { + } + + // chunk steps, given chunk + virtual void on_chunk(JS::Value chunk) override + { + // 1. Resolve promise with «[ "value" → chunk, "done" → false ]». + WebIDL::resolve_promise(m_realm, m_promise, JS::create_iterator_result_object(m_realm.vm(), chunk, false)); + } + + // close steps, given chunk + virtual void on_close(JS::Value chunk) override + { + // 1. Resolve promise with «[ "value" → chunk, "done" → true ]». + WebIDL::resolve_promise(m_realm, m_promise, JS::create_iterator_result_object(m_realm.vm(), chunk, true)); + } + + // error steps, given e + virtual void on_error(JS::Value error) override + { + // 1. Reject promise with e. + WebIDL::reject_promise(m_realm, m_promise, error); + } + +private: + virtual void visit_edges(Visitor& visitor) override + { + Base::visit_edges(visitor); + visitor.visit(m_realm); + visitor.visit(m_promise); + } + + JS::Realm& m_realm; + WebIDL::Promise& m_promise; +}; + +// https://streams.spec.whatwg.org/#byob-reader-read +WebIDL::ExceptionOr> ReadableStreamBYOBReader::read(JS::Value view_value) +{ + auto& realm = this->realm(); + + // FIXME: Support DataViews + auto& view = verify_cast(view_value.as_object()); + + // 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception. + if (view.byte_length() == 0) { + auto exception = JS::TypeError::create(realm, "Cannot read in an empty buffer"sv); + auto promise_capability = WebIDL::create_rejected_promise(realm, exception); + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + } + + // 2. If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a promise rejected with a TypeError exception. + if (view.viewed_array_buffer()->byte_length() == 0) { + auto exception = JS::TypeError::create(realm, "Cannot read in an empty buffer"sv); + auto promise_capability = WebIDL::create_rejected_promise(realm, exception); + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + } + + // 3. If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a promise rejected with a TypeError exception. + if (view.viewed_array_buffer()->is_detached()) { + auto exception = JS::TypeError::create(realm, "Cannot read in a detached buffer"sv); + auto promise_capability = WebIDL::create_rejected_promise(realm, exception); + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + } + + // 4. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. + if (!m_stream) { + auto exception = JS::TypeError::create(realm, "Cannot read from an empty stream"sv); + auto promise_capability = WebIDL::create_rejected_promise(realm, exception); + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + } + + // 5. Let promise be a new promise. + auto promise_capability = WebIDL::create_promise(realm); + + // 6. Let readIntoRequest be a new read-into request with the following items: + // chunk steps, given chunk + // Resolve promise with «[ "value" → chunk, "done" → false ]». + // close steps, given chunk + // Resolve promise with «[ "value" → chunk, "done" → true ]». + // error steps, given e + // Reject promise with e. + auto read_into_request = heap().allocate_without_realm(realm, promise_capability); + + // 7. Perform ! ReadableStreamBYOBReaderRead(this, view, readIntoRequest). + readable_stream_byob_reader_read(*this, view_value, *read_into_request); + + // 8. Return promise. + return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; +} } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h index 7bb973e5da..065e841e9e 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h @@ -44,6 +44,8 @@ public: virtual ~ReadableStreamBYOBReader() override = default; + WebIDL::ExceptionOr> read(JS::Value); + void release_lock(); Vector>& read_into_requests() { return m_read_into_requests; } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.idl b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.idl index 3cba0e3422..bde2126efd 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.idl +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.idl @@ -1,4 +1,5 @@ #import +#import #import // https://streams.spec.whatwg.org/#readablestreambyobreader @@ -6,7 +7,9 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); - // FIXME: Promise read(ArrayBufferView view); + // FIXME: This should accept an ArrayBufferView + Promise read(any view); + undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader;