Skip to content

Commit

Permalink
Bug 1864406 - Add ReadableStreamBYOBReader.prototype.read(view, { min…
Browse files Browse the repository at this point in the history
… }). r=saschanaz,webidl,smaug

Implements whatwg/streams#1145

Differential Revision: https://phabricator.services.mozilla.com/D226225
  • Loading branch information
evilpie committed Oct 28, 2024
1 parent 1b924e7 commit a6f55a1
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 325 deletions.
223 changes: 129 additions & 94 deletions dom/streams/ReadableByteStreamController.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dom/streams/ReadableByteStreamController.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerRespondWithNewView(

MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerPullInto(
JSContext* aCx, ReadableByteStreamController* aController,
JS::Handle<JSObject*> aView, ReadIntoRequest* aReadIntoRequest,
ErrorResult& aRv);
JS::Handle<JSObject*> aView, uint64_t aMin,
ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv);

void ReadableByteStreamControllerError(
ReadableByteStreamController* aController, JS::Handle<JS::Value> aValue,
Expand Down
55 changes: 44 additions & 11 deletions dom/streams/ReadableStreamBYOBReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ namespace streams_abstract {
// https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
void ReadableStreamBYOBReaderRead(JSContext* aCx,
ReadableStreamBYOBReader* aReader,
JS::Handle<JSObject*> aView,
JS::Handle<JSObject*> aView, uint64_t aMin,
ReadIntoRequest* aReadIntoRequest,
ErrorResult& aRv) {
// Step 1.Let stream be reader.[[stream]].
Expand All @@ -195,19 +195,20 @@ void ReadableStreamBYOBReaderRead(JSContext* aCx,
}

// Step 5. Otherwise, perform
// !ReadableByteStreamControllerPullInto(stream.[[controller]], view,
// !ReadableByteStreamControllerPullInto(stream.[[controller]], view, min,
// readIntoRequest).
MOZ_ASSERT(stream->Controller()->IsByte());
RefPtr<ReadableByteStreamController> controller(
stream->Controller()->AsByte());
ReadableByteStreamControllerPullInto(aCx, controller, aView, aReadIntoRequest,
aRv);
ReadableByteStreamControllerPullInto(aCx, controller, aView, aMin,
aReadIntoRequest, aRv);
}
} // namespace streams_abstract

// https://streams.spec.whatwg.org/#byob-reader-read
already_AddRefed<Promise> ReadableStreamBYOBReader::Read(
const ArrayBufferView& aArray, ErrorResult& aRv) {
const ArrayBufferView& aArray,
const ReadableStreamBYOBReaderReadOptions& aOptions, ErrorResult& aRv) {
AutoJSAPI jsapi;
if (!jsapi.Init(GetParentObject())) {
aRv.ThrowUnknownError("Internal error");
Expand Down Expand Up @@ -247,28 +248,60 @@ already_AddRefed<Promise> ReadableStreamBYOBReader::Read(
return nullptr;
}

// Step 4. If this.[[stream]] is undefined, return a promise rejected with a
// Step 4. If options["min"] is 0, return a promise rejected with a TypeError
// exception.
if (aOptions.mMin == 0) {
aRv.ThrowTypeError(
"Zero is not a valid value for 'min' member of "
"ReadableStreamBYOBReaderReadOptions.");
return nullptr;
}

// Step 5. If view has a [[TypedArrayName]] internal slot,
if (JS_IsTypedArrayObject(view)) {
// Step 5.1. If options["min"] > view.[[ArrayLength]], return a promise
// rejected with a RangeError exception.
if (aOptions.mMin > JS_GetTypedArrayLength(view)) {
aRv.ThrowRangeError(
"Array length exceeded by 'min' member of "
"ReadableStreamBYOBReaderReadOptions.");
return nullptr;
}
} else {
// Step 6. Otherwise (i.e., it is a DataView),
// Step 6.1. If options["min"] > view.[[ByteLength]], return a promise
// rejected with a RangeError exception.
if (aOptions.mMin > JS_GetArrayBufferViewByteLength(view)) {
aRv.ThrowRangeError(
"byteLength exceeded by 'min' member of "
"ReadableStreamBYOBReaderReadOptions.");
return nullptr;
}
}

// Step 7. If this.[[stream]] is undefined, return a promise rejected with a
// TypeError exception.
if (!GetStream()) {
aRv.ThrowTypeError("Reader has undefined stream");
return nullptr;
}

// Step 5.
// Step 8. Let promise be a new promise.
RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());

// Step 6. Let readIntoRequest be a new read-into request with the following
// Step 9. Let readIntoRequest be a new read-into request with the following
// items:
RefPtr<ReadIntoRequest> readIntoRequest = new Read_ReadIntoRequest(promise);

// Step 7. Perform ! ReadableStreamBYOBReaderRead(this, view,
// Step 10. Perform ! ReadableStreamBYOBReaderRead(this, view, options["min"],
// readIntoRequest).
ReadableStreamBYOBReaderRead(cx, this, view, readIntoRequest, aRv);
ReadableStreamBYOBReaderRead(cx, this, view, aOptions.mMin, readIntoRequest,
aRv);
if (aRv.Failed()) {
return nullptr;
}

// Step 8. Return promise.
// Step 11. Return promise.
return promise.forget();
}

Expand Down
8 changes: 5 additions & 3 deletions dom/streams/ReadableStreamBYOBReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace mozilla::dom {
class Promise;
struct ReadIntoRequest;
class ReadableStream;
struct ReadableStreamBYOBReaderReadOptions;

} // namespace mozilla::dom

Expand Down Expand Up @@ -52,7 +53,8 @@ class ReadableStreamBYOBReader final : public ReadableStreamGenericReader,
const GlobalObject& global, ReadableStream& stream, ErrorResult& rv);

MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> Read(
const ArrayBufferView& aArray, ErrorResult& rv);
const ArrayBufferView& aArray,
const ReadableStreamBYOBReaderReadOptions& aOptions, ErrorResult& rv);

void ReleaseLock(ErrorResult& rv);

Expand All @@ -73,8 +75,8 @@ already_AddRefed<ReadableStreamBYOBReader> AcquireReadableStreamBYOBReader(

MOZ_CAN_RUN_SCRIPT void ReadableStreamBYOBReaderRead(
JSContext* aCx, ReadableStreamBYOBReader* aReader,
JS::Handle<JSObject*> aView, ReadIntoRequest* aReadIntoRequest,
ErrorResult& aRv);
JS::Handle<JSObject*> aView, uint64_t aMin,
ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv);

void ReadableStreamBYOBReaderErrorReadIntoRequests(
JSContext* aCx, ReadableStreamBYOBReader* aReader,
Expand Down
5 changes: 3 additions & 2 deletions dom/streams/ReadableStreamTee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,10 +911,11 @@ void PullWithBYOBReader(JSContext* aCx, TeeState* aTeeState,
RefPtr<ReadIntoRequest> readIntoRequest =
new PullWithBYOBReader_ReadIntoRequest(aTeeState, aForBranch);

// Step 16.5.
// Step 16.5. Perform ! ReadableStreamBYOBReaderRead(reader, view, 1,
// readIntoRequest).
RefPtr<ReadableStreamBYOBReader> byobReader =
aTeeState->GetReader()->AsBYOB();
ReadableStreamBYOBReaderRead(aCx, byobReader, aView, readIntoRequest, aRv);
ReadableStreamBYOBReaderRead(aCx, byobReader, aView, 1, readIntoRequest, aRv);
}

// See https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamtee
Expand Down
6 changes: 5 additions & 1 deletion dom/webidl/ReadableStreamBYOBReader.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ interface ReadableStreamBYOBReader {
constructor(ReadableStream stream);

[NewObject]
Promise<ReadableStreamReadResult> read(ArrayBufferView view);
Promise<ReadableStreamReadResult> read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {});

[Throws]
undefined releaseLock();
};
ReadableStreamBYOBReader includes ReadableStreamGenericReader;

dictionary ReadableStreamBYOBReaderReadOptions {
[EnforceRange] unsigned long long min = 1;
};
Original file line number Diff line number Diff line change
@@ -1,214 +1,2 @@
[read-min.any.worker.html]
[ReadableStream with byte source: read({ min }) rejects if min is 0]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is negative]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
expected: FAIL
[ReadableStream with byte source: read({ min }), then read()]
expected: FAIL
[ReadableStream with byte source: read({ min }) with a DataView]
expected: FAIL
[ReadableStream with byte source: enqueue(), then read({ min })]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min }) when closed before view is filled]
expected: FAIL
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
expected: FAIL
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
expected: FAIL
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
expected: FAIL
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
expected: FAIL
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
expected: FAIL
[read-min.any.html]
[ReadableStream with byte source: read({ min }) rejects if min is 0]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is negative]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
expected: FAIL

[ReadableStream with byte source: read({ min }), then read()]
expected: FAIL

[ReadableStream with byte source: read({ min }) with a DataView]
expected: FAIL

[ReadableStream with byte source: enqueue(), then read({ min })]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min }) when closed before view is filled]
expected: FAIL

[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
expected: FAIL

[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
expected: FAIL

[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
expected: FAIL

[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
expected: FAIL

[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
expected: FAIL


[read-min.any.serviceworker.html]
[ReadableStream with byte source: read({ min }) rejects if min is 0]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is negative]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
expected: FAIL
[ReadableStream with byte source: read({ min }), then read()]
expected: FAIL
[ReadableStream with byte source: read({ min }) with a DataView]
expected: FAIL
[ReadableStream with byte source: enqueue(), then read({ min })]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
expected: FAIL
[ReadableStream with byte source: read({ min }) when closed before view is filled]
expected: FAIL
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
expected: FAIL
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
expected: FAIL
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
expected: FAIL
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
expected: FAIL
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
expected: FAIL
[read-min.any.sharedworker.html]
[ReadableStream with byte source: read({ min }) rejects if min is 0]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is negative]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
expected: FAIL

[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
expected: FAIL
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
expected: FAIL

[ReadableStream with byte source: read({ min }), then read()]
expected: FAIL

[ReadableStream with byte source: read({ min }) with a DataView]
expected: FAIL

[ReadableStream with byte source: enqueue(), then read({ min })]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
expected: FAIL

[ReadableStream with byte source: read({ min }) when closed before view is filled]
expected: FAIL

[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
expected: FAIL

[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
expected: FAIL

[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
expected: FAIL

[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
expected: FAIL

[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
expected: FAIL


[read-min.any.shadowrealm.html]
expected: ERROR

0 comments on commit a6f55a1

Please sign in to comment.