LibWeb: Use ArrayBufferView for ReadableStreamBYOBReader

Which means that we now have support for DataViews.

Using the ArrayBufferView class also seems to make this read a whole
bunch nicer as well.
This commit is contained in:
Shannon Booth 2023-11-23 21:48:28 +13:00 committed by Andreas Kling
parent eab20129b9
commit 673329e1bd
Notes: sideshowbarker 2024-07-17 08:45:34 +09:00
7 changed files with 41 additions and 37 deletions

View File

@ -1,3 +1,6 @@
About to read! [object ReadableStreamBYOBReader]
About to read into Uint8Array with [object ReadableStreamBYOBReader]
Total bytes: 34
'This is some data to be read! 🦬'
About to read into DataView with [object ReadableStreamBYOBReader]
Total bytes: 34
'This is some data to be read! 🦬'

View File

@ -1,6 +1,6 @@
<script src="../include.js"></script>
<script>
asyncTest(async done => {
async function testByobRead(type) {
const array = ['This is some data to be read! 🦬'];
let blob = new Blob(array);
@ -11,15 +11,14 @@
let bytesReceived = 0;
let offset = 0;
println(`About to read! ${reader}`);
println(`About to read into ${type.prototype.constructor.name} with ${reader}`);
while (true) {
let result = await reader.read(new Uint8Array(buffer, offset, buffer.byteLength - offset));
let result = await reader.read(new type(buffer, offset, buffer.byteLength - offset));
if (result.done) {
println(`Total bytes: ${bytesReceived}`);
println(`'${new TextDecoder().decode(result.value.buffer.slice(0, bytesReceived))}'`);
done();
return;
}
@ -27,5 +26,11 @@
offset += result.value.byteLength;
bytesReceived += result.value.byteLength;
}
}
asyncTest(async done => {
await testByobRead(Uint8Array);
await testByobRead(DataView);
done();
});
</script>

View File

@ -34,6 +34,7 @@
#include <LibWeb/Streams/WritableStreamDefaultController.h>
#include <LibWeb/Streams/WritableStreamDefaultWriter.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/WebIDL/Promise.h>
@ -659,15 +660,11 @@ JS::Value readable_byte_stream_controller_convert_pull_into_descriptor(JS::Realm
}
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
void readable_byte_stream_controller_pull_into(ReadableByteStreamController& controller, JS::Value view_value, ReadIntoRequest& read_into_request)
void readable_byte_stream_controller_pull_into(ReadableByteStreamController& controller, WebIDL::ArrayBufferView& view, ReadIntoRequest& read_into_request)
{
auto& vm = controller.vm();
auto& realm = controller.realm();
// FIXME: Support DataView
auto& view_object = view_value.as_object();
auto const& view = verify_cast<JS::TypedArrayBase>(view_object);
// 1. Let stream be controller.[[stream]].
auto stream = controller.stream();
@ -678,32 +675,34 @@ void readable_byte_stream_controller_pull_into(ReadableByteStreamController& con
JS::NativeFunction* ctor = realm.intrinsics().data_view_constructor();
// 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a DataView),
if (!is<JS::DataView>(view_object)) {
if (view.bufferable_object().has<JS::NonnullGCPtr<JS::TypedArrayBase>>()) {
auto const& typed_array = view.bufferable_object().get<JS::NonnullGCPtr<JS::TypedArrayBase>>();
// 1. Set elementSize to the element size specified in the typed array constructors table for view.[[TypedArrayName]].
element_size = view.element_size();
element_size = typed_array->element_size();
// 2. Set ctor to the constructor specified in the typed array constructors table for view.[[TypedArrayName]].
if (is<JS::Int16Array>(view_object))
if (is<JS::Int16Array>(*typed_array))
ctor = realm.intrinsics().int16_array_constructor();
else if (is<JS::Int32Array>(view_object))
else if (is<JS::Int32Array>(*typed_array))
ctor = realm.intrinsics().int32_array_constructor();
else if (is<JS::Int8Array>(view_object))
else if (is<JS::Int8Array>(*typed_array))
ctor = realm.intrinsics().int8_array_constructor();
else if (is<JS::Uint8Array>(view_object))
else if (is<JS::Uint8Array>(*typed_array))
ctor = realm.intrinsics().uint8_array_constructor();
else if (is<JS::Uint16Array>(view_object))
else if (is<JS::Uint16Array>(*typed_array))
ctor = realm.intrinsics().uint16_array_constructor();
else if (is<JS::Uint32Array>(view_object))
else if (is<JS::Uint32Array>(*typed_array))
ctor = realm.intrinsics().uint32_array_constructor();
else if (is<JS::Uint8ClampedArray>(view_object))
else if (is<JS::Uint8ClampedArray>(*typed_array))
ctor = realm.intrinsics().uint8_clamped_array_constructor();
else if (is<JS::BigInt64Array>(view_object))
else if (is<JS::BigInt64Array>(*typed_array))
ctor = realm.intrinsics().big_int64_array_constructor();
else if (is<JS::BigUint64Array>(view_object))
else if (is<JS::BigUint64Array>(*typed_array))
ctor = realm.intrinsics().big_uint64_array_constructor();
else if (is<JS::Float32Array>(view_object))
else if (is<JS::Float32Array>(*typed_array))
ctor = realm.intrinsics().float32_array_constructor();
else if (is<JS::Float64Array>(view_object))
else if (is<JS::Float64Array>(*typed_array))
ctor = realm.intrinsics().float64_array_constructor();
else
VERIFY_NOT_REACHED();
@ -812,7 +811,7 @@ void readable_byte_stream_controller_pull_into(ReadableByteStreamController& con
}
// https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
void readable_stream_byob_reader_read(ReadableStreamBYOBReader& reader, JS::Value view, ReadIntoRequest& read_into_request)
void readable_stream_byob_reader_read(ReadableStreamBYOBReader& reader, WebIDL::ArrayBufferView& view, ReadIntoRequest& read_into_request)
{
// 1. Let stream be reader.[[stream]].
auto stream = reader.stream();

View File

@ -54,8 +54,8 @@ WebIDL::ExceptionOr<void> readable_stream_reader_generic_release(ReadableStreamG
void readable_stream_default_reader_error_read_requests(ReadableStreamDefaultReader&, JS::Value error);
void readable_stream_byob_reader_error_read_into_requests(ReadableStreamBYOBReader&, JS::Value error);
JS::Value readable_byte_stream_controller_convert_pull_into_descriptor(JS::Realm&, PullIntoDescriptor const&);
void readable_byte_stream_controller_pull_into(ReadableByteStreamController&, JS::Value view_value, ReadIntoRequest&);
void readable_stream_byob_reader_read(ReadableStreamBYOBReader&, JS::Value view, ReadIntoRequest&);
void readable_byte_stream_controller_pull_into(ReadableByteStreamController&, WebIDL::ArrayBufferView&, ReadIntoRequest&);
void readable_stream_byob_reader_read(ReadableStreamBYOBReader&, WebIDL::ArrayBufferView&, ReadIntoRequest&);
void readable_byte_stream_controller_fill_head_pull_into_descriptor(ReadableByteStreamController const&, u64 size, PullIntoDescriptor&);
WebIDL::ExceptionOr<void> readable_stream_default_reader_read(ReadableStreamDefaultReader&, ReadRequest&);

View File

@ -11,6 +11,7 @@
#include <LibWeb/Streams/AbstractOperations.h>
#include <LibWeb/Streams/ReadableStream.h>
#include <LibWeb/Streams/ReadableStreamBYOBReader.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::Streams {
@ -103,29 +104,26 @@ private:
};
// https://streams.spec.whatwg.org/#byob-reader-read
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ReadableStreamBYOBReader::read(JS::Value view_value)
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::ArrayBufferView>& view)
{
auto& realm = this->realm();
// FIXME: Support DataViews
auto& view = verify_cast<JS::TypedArrayBase>(view_value.as_object());
// 1. If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception.
if (view.byte_length() == 0) {
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<JS::Promise>(*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) {
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<JS::Promise>(*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()) {
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<JS::Promise>(*promise_capability->promise()) };
@ -151,7 +149,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ReadableStreamBYOBReader::rea
auto read_into_request = heap().allocate_without_realm<BYOBReaderReadIntoRequest>(realm, promise_capability);
// 7. Perform ! ReadableStreamBYOBReaderRead(this, view, readIntoRequest).
readable_stream_byob_reader_read(*this, view_value, *read_into_request);
readable_stream_byob_reader_read(*this, *view, *read_into_request);
// 8. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise()) };

View File

@ -45,7 +45,7 @@ public:
virtual ~ReadableStreamBYOBReader() override = default;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> read(JS::Value);
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> read(JS::Handle<WebIDL::ArrayBufferView>&);
void release_lock();

View File

@ -7,8 +7,7 @@
interface ReadableStreamBYOBReader {
constructor(ReadableStream stream);
// FIXME: This should accept an ArrayBufferView
Promise<ReadableStreamReadResult> read(any view);
Promise<ReadableStreamReadResult> read(ArrayBufferView view);
undefined releaseLock();
};