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;