mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1864406 - Add ReadableStreamBYOBReader.prototype.read(view, { min }). r=saschanaz,webidl,smaug
Implements https://github.com/whatwg/streams/pull/1145 Differential Revision: https://phabricator.services.mozilla.com/D226225
This commit is contained in:
parent
319c8cab75
commit
a140dbde6f
@ -115,13 +115,15 @@ struct PullIntoDescriptor final
|
||||
|
||||
PullIntoDescriptor(JS::Handle<JSObject*> aBuffer, uint64_t aBufferByteLength,
|
||||
uint64_t aByteOffset, uint64_t aByteLength,
|
||||
uint64_t aBytesFilled, uint64_t aElementSize,
|
||||
Constructor aViewConstructor, ReaderType aReaderType)
|
||||
uint64_t aBytesFilled, uint64_t aMinimumFill,
|
||||
uint64_t aElementSize, Constructor aViewConstructor,
|
||||
ReaderType aReaderType)
|
||||
: mBuffer(aBuffer),
|
||||
mBufferByteLength(aBufferByteLength),
|
||||
mByteOffset(aByteOffset),
|
||||
mByteLength(aByteLength),
|
||||
mBytesFilled(aBytesFilled),
|
||||
mMinimumFill(aMinimumFill),
|
||||
mElementSize(aElementSize),
|
||||
mViewConstructor(aViewConstructor),
|
||||
mReaderType(aReaderType) {
|
||||
@ -147,6 +149,8 @@ struct PullIntoDescriptor final
|
||||
mBytesFilled = aBytesFilled;
|
||||
}
|
||||
|
||||
uint64_t MinimumFill() const { return mMinimumFill; }
|
||||
|
||||
uint64_t ElementSize() const { return mElementSize; }
|
||||
void SetElementSize(const uint64_t aElementSize) {
|
||||
mElementSize = aElementSize;
|
||||
@ -166,6 +170,7 @@ struct PullIntoDescriptor final
|
||||
uint64_t mByteOffset = 0;
|
||||
uint64_t mByteLength = 0;
|
||||
uint64_t mBytesFilled = 0;
|
||||
uint64_t mMinimumFill = 0;
|
||||
uint64_t mElementSize = 0;
|
||||
Constructor mViewConstructor;
|
||||
ReaderType mReaderType;
|
||||
@ -394,11 +399,14 @@ void ReadableByteStreamControllerClose(
|
||||
|
||||
// Step 4.
|
||||
if (!aController->PendingPullIntos().isEmpty()) {
|
||||
// Step 4.1
|
||||
// Step 4.1. Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
|
||||
PullIntoDescriptor* firstPendingPullInto =
|
||||
aController->PendingPullIntos().getFirst();
|
||||
// Step 4.2
|
||||
if (firstPendingPullInto->BytesFilled() > 0) {
|
||||
|
||||
// Step 4.2. If the remainder after dividing firstPendingPullInto’s bytes
|
||||
// filled by firstPendingPullInto’s element size is not 0,
|
||||
if ((firstPendingPullInto->BytesFilled() %
|
||||
firstPendingPullInto->ElementSize()) != 0) {
|
||||
// Step 4.2.1
|
||||
ErrorResult rv;
|
||||
rv.ThrowTypeError("Leftover Bytes");
|
||||
@ -703,8 +711,10 @@ void ReadableByteStreamControllerCommitPullIntoDescriptor(
|
||||
|
||||
// Step 4. If stream.[[state]] is "closed",
|
||||
if (aStream->State() == ReadableStream::ReaderState::Closed) {
|
||||
// Step 4.1. Assert: pullIntoDescriptor’s bytes filled is 0.
|
||||
MOZ_ASSERT(pullIntoDescriptor->BytesFilled() == 0);
|
||||
// Step 4.1. Assert: the remainder after dividing pullIntoDescriptor’s bytes
|
||||
// filled by pullIntoDescriptor’s element size is 0.
|
||||
MOZ_ASSERT((pullIntoDescriptor->BytesFilled() %
|
||||
pullIntoDescriptor->ElementSize()) == 0);
|
||||
|
||||
// Step 4.2. Set done to true.
|
||||
done = true;
|
||||
@ -1144,13 +1154,13 @@ void ReadableByteStreamControllerHandleQueueDrain(
|
||||
void ReadableByteStreamController::PullSteps(JSContext* aCx,
|
||||
ReadRequest* aReadRequest,
|
||||
ErrorResult& aRv) {
|
||||
// Step 1.
|
||||
// Step 1. Let stream be this.[[stream]].
|
||||
ReadableStream* stream = Stream();
|
||||
|
||||
// Step 2.
|
||||
// Step 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true.
|
||||
MOZ_ASSERT(ReadableStreamHasDefaultReader(stream));
|
||||
|
||||
// Step 3.
|
||||
// Step 3. If this.[[queueTotalSize]] > 0,
|
||||
if (QueueTotalSize() > 0) {
|
||||
// Step 3.1. Assert: ! ReadableStreamGetNumReadRequests ( stream ) is 0.
|
||||
MOZ_ASSERT(ReadableStreamGetNumReadRequests(stream) == 0);
|
||||
@ -1164,18 +1174,20 @@ void ReadableByteStreamController::PullSteps(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
// Step 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
|
||||
Maybe<uint64_t> autoAllocateChunkSize = AutoAllocateChunkSize();
|
||||
|
||||
// Step 5.
|
||||
// Step 5. If autoAllocateChunkSize is not undefined,
|
||||
if (autoAllocateChunkSize) {
|
||||
// Step 5.1
|
||||
// Step 5.1. Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize
|
||||
// »).
|
||||
aRv.MightThrowJSException();
|
||||
JS::Rooted<JSObject*> buffer(
|
||||
aCx, JS::NewArrayBuffer(aCx, *autoAllocateChunkSize));
|
||||
// Step 5.2
|
||||
|
||||
// Step 5.2. If buffer is an abrupt completion,
|
||||
if (!buffer) {
|
||||
// Step 5.2.1
|
||||
// Step 5.2.1. Perform readRequest’s error steps, given buffer.[[Value]].
|
||||
JS::Rooted<JS::Value> bufferError(aCx);
|
||||
if (!JS_GetPendingException(aCx, &bufferError)) {
|
||||
// Uncatchable exception; we should mark aRv and return.
|
||||
@ -1183,29 +1195,40 @@ void ReadableByteStreamController::PullSteps(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
// It's not expliclitly stated, but I assume the intention here is that
|
||||
// It's not explicitly stated, but I assume the intention here is that
|
||||
// we perform a normal completion here.
|
||||
JS_ClearPendingException(aCx);
|
||||
|
||||
aReadRequest->ErrorSteps(aCx, bufferError, aRv);
|
||||
|
||||
// Step 5.2.2.
|
||||
// Step 5.2.2. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 5.3
|
||||
// Step 5.3 Let pullIntoDescriptor be a new pull-into descriptor with
|
||||
// buffer buffer.[[Value]]
|
||||
// buffer byte length autoAllocateChunkSize
|
||||
// byte offset 0
|
||||
// byte length autoAllocateChunkSize
|
||||
// bytes filled 0
|
||||
// minimum fill 1
|
||||
// element size 1
|
||||
// view constructor %Uint8Array%
|
||||
// reader type "default"
|
||||
RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor(
|
||||
buffer, *autoAllocateChunkSize, 0, *autoAllocateChunkSize, 0, 1,
|
||||
buffer, /* aBufferByteLength */ *autoAllocateChunkSize,
|
||||
/*aByteOffset */ 0, /* aByteLength */ *autoAllocateChunkSize,
|
||||
/* aBytesFilled */ 0, /* aMinimumFill */ 1, /* aElementSize */ 1,
|
||||
PullIntoDescriptor::Constructor::Uint8, ReaderType::Default);
|
||||
|
||||
// Step 5.4
|
||||
// Step 5.4. Append pullIntoDescriptor to this.[[pendingPullIntos]].
|
||||
PendingPullIntos().insertBack(pullIntoDescriptor);
|
||||
}
|
||||
|
||||
// Step 6.
|
||||
// Step 6. Perform ! ReadableStreamAddReadRequest(stream, readRequest).
|
||||
ReadableStreamAddReadRequest(stream, aReadRequest);
|
||||
|
||||
// Step 7.
|
||||
// Step 7. Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
|
||||
ReadableByteStreamControllerCallPullIfNeeded(aCx, this, aRv);
|
||||
}
|
||||
|
||||
@ -1280,7 +1303,8 @@ JSObject* ReadableByteStreamControllerConvertPullIntoDescriptor(
|
||||
// Step 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
|
||||
MOZ_ASSERT(bytesFilled <= pullIntoDescriptor->ByteLength());
|
||||
|
||||
// Step 4. Assert: bytesFilled mod elementSize is 0.
|
||||
// Step 4. Assert: the remainder after dividing bytesFilled by elementSize is
|
||||
// 0.
|
||||
MOZ_ASSERT(bytesFilled % elementSize == 0);
|
||||
|
||||
// Step 5. Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).
|
||||
@ -1310,8 +1334,10 @@ MOZ_CAN_RUN_SCRIPT
|
||||
static void ReadableByteStreamControllerRespondInClosedState(
|
||||
JSContext* aCx, ReadableByteStreamController* aController,
|
||||
RefPtr<PullIntoDescriptor>& aFirstDescriptor, ErrorResult& aRv) {
|
||||
// Step 1. Assert: firstDescriptor ’s bytes filled is 0.
|
||||
MOZ_ASSERT(aFirstDescriptor->BytesFilled() == 0);
|
||||
// Step 1. Assert: the remainder after dividing firstDescriptor’s bytes filled
|
||||
// by firstDescriptor’s element size is 0.
|
||||
MOZ_ASSERT(
|
||||
(aFirstDescriptor->BytesFilled() % aFirstDescriptor->ElementSize()) == 0);
|
||||
|
||||
// Step 2. If firstDescriptor’s reader type is "none",
|
||||
// perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
|
||||
@ -1396,9 +1422,9 @@ static void ReadableByteStreamControllerRespondInReadableState(
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s element
|
||||
// size, return.
|
||||
if (aPullIntoDescriptor->BytesFilled() < aPullIntoDescriptor->ElementSize()) {
|
||||
// Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum
|
||||
// fill, return.
|
||||
if (aPullIntoDescriptor->BytesFilled() < aPullIntoDescriptor->MinimumFill()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1408,8 +1434,8 @@ static void ReadableByteStreamControllerRespondInReadableState(
|
||||
ReadableByteStreamControllerShiftPendingPullInto(aController);
|
||||
(void)pullIntoDescriptor;
|
||||
|
||||
// Step 6. Let remainderSize be pullIntoDescriptor’s bytes filled mod
|
||||
// pullIntoDescriptor’s element size.
|
||||
// Step 6. Let remainderSize be the remainder after dividing
|
||||
// pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size.
|
||||
size_t remainderSize =
|
||||
aPullIntoDescriptor->BytesFilled() % aPullIntoDescriptor->ElementSize();
|
||||
|
||||
@ -1647,38 +1673,37 @@ void ReadableByteStreamControllerRespondWithNewView(
|
||||
bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
|
||||
JSContext* aCx, ReadableByteStreamController* aController,
|
||||
PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv) {
|
||||
// Step 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
|
||||
size_t elementSize = aPullIntoDescriptor->ElementSize();
|
||||
|
||||
// Step 2. Let currentAlignedBytes be pullIntoDescriptor’s bytes filled −
|
||||
// (pullIntoDescriptor’s bytes filled mod elementSize).
|
||||
size_t currentAlignedBytes =
|
||||
aPullIntoDescriptor->BytesFilled() -
|
||||
(aPullIntoDescriptor->BytesFilled() % elementSize);
|
||||
|
||||
// Step 3. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
|
||||
// Step 1. Let maxBytesToCopy be min(controller.[[queueTotalSize]],
|
||||
// pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
|
||||
size_t maxBytesToCopy =
|
||||
std::min(static_cast<size_t>(aController->QueueTotalSize()),
|
||||
static_cast<size_t>((aPullIntoDescriptor->ByteLength() -
|
||||
aPullIntoDescriptor->BytesFilled())));
|
||||
|
||||
// Step 4. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
|
||||
// Step 2. Let maxBytesFilled be pullIntoDescriptor’s bytes filled +
|
||||
// maxBytesToCopy.
|
||||
size_t maxBytesFilled = aPullIntoDescriptor->BytesFilled() + maxBytesToCopy;
|
||||
|
||||
// Step 5. Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod
|
||||
// elementSize).
|
||||
size_t maxAlignedBytes = maxBytesFilled - (maxBytesFilled % elementSize);
|
||||
|
||||
// Step 6. Let totalBytesToCopyRemaining be maxBytesToCopy.
|
||||
// Step 3. Let totalBytesToCopyRemaining be maxBytesToCopy.
|
||||
size_t totalBytesToCopyRemaining = maxBytesToCopy;
|
||||
|
||||
// Step 7. Let ready be false.
|
||||
// Step 4. Let ready be false.
|
||||
bool ready = false;
|
||||
|
||||
// Step 8. If maxAlignedBytes > currentAlignedBytes,
|
||||
if (maxAlignedBytes > currentAlignedBytes) {
|
||||
// Step 5. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s
|
||||
// minimum fill.
|
||||
MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() <
|
||||
aPullIntoDescriptor->MinimumFill());
|
||||
|
||||
// Step 6. Let remainderBytes be the remainder after dividing maxBytesFilled
|
||||
// by pullIntoDescriptor’s element size.
|
||||
size_t remainderBytes = maxBytesFilled % aPullIntoDescriptor->ElementSize();
|
||||
|
||||
// Step 7. Let maxAlignedBytes be maxBytesFilled − remainderBytes.
|
||||
size_t maxAlignedBytes = maxBytesFilled - remainderBytes;
|
||||
|
||||
// Step 8. If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill,
|
||||
if (maxAlignedBytes >= aPullIntoDescriptor->MinimumFill()) {
|
||||
// Step 8.1. Set totalBytesToCopyRemaining to maxAlignedBytes −
|
||||
// pullIntoDescriptor’s bytes filled.
|
||||
totalBytesToCopyRemaining =
|
||||
@ -1758,10 +1783,9 @@ bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
|
||||
MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() > 0);
|
||||
|
||||
// Step 11.3. Assert: pullIntoDescriptor’s bytes filled <
|
||||
// pullIntoDescriptor’s
|
||||
// element size.
|
||||
// pullIntoDescriptor’s minimum fill.
|
||||
MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() <
|
||||
aPullIntoDescriptor->ElementSize());
|
||||
aPullIntoDescriptor->MinimumFill());
|
||||
}
|
||||
|
||||
// Step 12. Return ready.
|
||||
@ -1771,8 +1795,8 @@ bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
|
||||
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into
|
||||
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) {
|
||||
aRv.MightThrowJSException();
|
||||
|
||||
// Step 1. Let stream be controller.[[stream]].
|
||||
@ -1798,13 +1822,23 @@ void ReadableByteStreamControllerPullInto(
|
||||
ctor = PullIntoDescriptor::constructorFromScalar(type);
|
||||
}
|
||||
|
||||
// Step 5. Let byteOffset be view.[[ByteOffset]].
|
||||
// Step 5. Let minimumFill be min × elementSize.
|
||||
uint64_t minimumFill = aMin * elementSize;
|
||||
|
||||
// Step 6. Assert: minimumFill ≥ 0 and minimumFill ≤ view.[[ByteLength]].
|
||||
MOZ_ASSERT(minimumFill <= JS_GetArrayBufferViewByteLength(aView));
|
||||
|
||||
// Step 7. Assert: the remainder after dividing minimumFill by elementSize is
|
||||
// 0.
|
||||
MOZ_ASSERT((minimumFill % elementSize) == 0);
|
||||
|
||||
// Step 8. Let byteOffset be view.[[ByteOffset]].
|
||||
size_t byteOffset = JS_GetArrayBufferViewByteOffset(aView);
|
||||
|
||||
// Step 6. Let byteLength be view.[[ByteLength]].
|
||||
// Step 9. Let byteLength be view.[[ByteLength]].
|
||||
size_t byteLength = JS_GetArrayBufferViewByteLength(aView);
|
||||
|
||||
// Step 7. Let bufferResult be
|
||||
// Step 10. Let bufferResult be
|
||||
// TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
|
||||
bool isShared;
|
||||
JS::Rooted<JSObject*> viewedArrayBuffer(
|
||||
@ -1816,7 +1850,7 @@ void ReadableByteStreamControllerPullInto(
|
||||
JS::Rooted<JSObject*> bufferResult(
|
||||
aCx, TransferArrayBuffer(aCx, viewedArrayBuffer));
|
||||
|
||||
// Step 8. If bufferResult is an abrupt completion,
|
||||
// Step 11. If bufferResult is an abrupt completion,
|
||||
if (!bufferResult) {
|
||||
JS::Rooted<JS::Value> pendingException(aCx);
|
||||
if (!JS_GetPendingException(aCx, &pendingException)) {
|
||||
@ -1831,46 +1865,47 @@ void ReadableByteStreamControllerPullInto(
|
||||
// exception state anyhow to succesfully run ErrorSteps.
|
||||
JS_ClearPendingException(aCx);
|
||||
|
||||
// Step 8.1. Perform readIntoRequest’s error steps, given
|
||||
// Step 11.1. Perform readIntoRequest’s error steps, given
|
||||
// bufferResult.[[Value]].
|
||||
aReadIntoRequest->ErrorSteps(aCx, pendingException, aRv);
|
||||
|
||||
// Step 8.2. Return.
|
||||
// Step 11.2. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 9. Let buffer be bufferResult.[[Value]].
|
||||
// Step 12. Let buffer be bufferResult.[[Value]].
|
||||
JS::Rooted<JSObject*> buffer(aCx, bufferResult);
|
||||
|
||||
// Step 10. Let pullIntoDescriptor be a new pull-into descriptor with
|
||||
// buffer: buffer,
|
||||
// buffer byte length: buffer.[[ArrayBufferByteLength]],
|
||||
// byte offset: byteOffset,
|
||||
// byte length: byteLength,
|
||||
// bytes filled: 0,
|
||||
// element size: elementSize,
|
||||
// view constructor: ctor,
|
||||
// and reader type: "byob".
|
||||
// Step 13. Let pullIntoDescriptor be a new pull-into descriptor with
|
||||
// buffer: buffer
|
||||
// buffer byte length: buffer.[[ArrayBufferByteLength]]
|
||||
// byte offset: byteOffset
|
||||
// byte length: byteLength
|
||||
// bytes filled: 0
|
||||
// minimum fill: minimumFill
|
||||
// element size: elementSize
|
||||
// view constructor: ctor
|
||||
// reader type: "byob"
|
||||
RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor(
|
||||
buffer, JS::GetArrayBufferByteLength(buffer), byteOffset, byteLength, 0,
|
||||
elementSize, ctor, ReaderType::BYOB);
|
||||
minimumFill, elementSize, ctor, ReaderType::BYOB);
|
||||
|
||||
// Step 11. If controller.[[pendingPullIntos]] is not empty,
|
||||
// Step 14. If controller.[[pendingPullIntos]] is not empty,
|
||||
if (!aController->PendingPullIntos().isEmpty()) {
|
||||
// Step 11.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
|
||||
// Step 14.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
|
||||
aController->PendingPullIntos().insertBack(pullIntoDescriptor);
|
||||
|
||||
// Step 11.2. Perform !ReadableStreamAddReadIntoRequest(stream,
|
||||
// Step 14.2. Perform !ReadableStreamAddReadIntoRequest(stream,
|
||||
// readIntoRequest).
|
||||
ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest);
|
||||
|
||||
// Step 11.3. Return.
|
||||
// Step 14.3. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 12. If stream.[[state]] is "closed",
|
||||
// Step 15. If stream.[[state]] is "closed",
|
||||
if (stream->State() == ReadableStream::ReaderState::Closed) {
|
||||
// Step 12.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s
|
||||
// Step 15.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s
|
||||
// buffer, pullIntoDescriptor’s byte offset, 0 »).
|
||||
JS::Rooted<JSObject*> pullIntoBuffer(aCx, pullIntoDescriptor->Buffer());
|
||||
JS::Rooted<JSObject*> emptyView(
|
||||
@ -1882,17 +1917,17 @@ void ReadableByteStreamControllerPullInto(
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 12.2. Perform readIntoRequest’s close steps, given emptyView.
|
||||
// Step 15.2. Perform readIntoRequest’s close steps, given emptyView.
|
||||
JS::Rooted<JS::Value> emptyViewValue(aCx, JS::ObjectValue(*emptyView));
|
||||
aReadIntoRequest->CloseSteps(aCx, emptyViewValue, aRv);
|
||||
|
||||
// Step 12.3. Return.
|
||||
// Step 15.3. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 13,. If controller.[[queueTotalSize]] > 0,
|
||||
// Step 16. If controller.[[queueTotalSize]] > 0,
|
||||
if (aController->QueueTotalSize() > 0) {
|
||||
// Step 13.1 If
|
||||
// Step 16.1 If
|
||||
// !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
|
||||
// pullIntoDescriptor) is true,
|
||||
bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
|
||||
@ -1901,7 +1936,7 @@ void ReadableByteStreamControllerPullInto(
|
||||
return;
|
||||
}
|
||||
if (ready) {
|
||||
// Step 13.1.1 Let filledView be
|
||||
// Step 16.1.1 Let filledView be
|
||||
// !ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
|
||||
JS::Rooted<JSObject*> filledView(
|
||||
aCx, ReadableByteStreamControllerConvertPullIntoDescriptor(
|
||||
@ -1909,51 +1944,50 @@ void ReadableByteStreamControllerPullInto(
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
// Step 13.1.2. Perform
|
||||
// Step 16.1.2. Perform
|
||||
// !ReadableByteStreamControllerHandleQueueDrain(controller).
|
||||
ReadableByteStreamControllerHandleQueueDrain(aCx, aController, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
// Step 13.1.3. Perform readIntoRequest’s chunk steps, given filledView.
|
||||
// Step 16.1.3. Perform readIntoRequest’s chunk steps, given filledView.
|
||||
JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView));
|
||||
aReadIntoRequest->ChunkSteps(aCx, filledViewValue, aRv);
|
||||
// Step 13.1.4. Return.
|
||||
// Step 16.1.4. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 13.2 If controller.[[closeRequested]] is true,
|
||||
// Step 16.2 If controller.[[closeRequested]] is true,
|
||||
if (aController->CloseRequested()) {
|
||||
// Step 13.2.1. Let e be a TypeError exception.
|
||||
// Step 16.2.1. Let e be a TypeError exception.
|
||||
ErrorResult typeError;
|
||||
typeError.ThrowTypeError("Close Requested True during Pull Into");
|
||||
|
||||
JS::Rooted<JS::Value> e(aCx);
|
||||
MOZ_RELEASE_ASSERT(ToJSValue(aCx, std::move(typeError), &e));
|
||||
|
||||
// Step 13.2.2. Perform !ReadableByteStreamControllerError(controller, e).
|
||||
// Step 16.2.2. Perform !ReadableByteStreamControllerError(controller, e).
|
||||
ReadableByteStreamControllerError(aController, e, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 13.2.3. Perform readIntoRequest’s error steps, given e.
|
||||
// Step 16.2.3. Perform readIntoRequest’s error steps, given e.
|
||||
aReadIntoRequest->ErrorSteps(aCx, e, aRv);
|
||||
|
||||
// Step 13.2.4. Return.
|
||||
// Step 16.2.4. Return.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 14. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
|
||||
// Step 17. Append pullIntoDescriptor to controller.[[pendingPullIntos]].
|
||||
aController->PendingPullIntos().insertBack(pullIntoDescriptor);
|
||||
|
||||
// Step 15. Perform !ReadableStreamAddReadIntoRequest(stream,
|
||||
// Step 18. Perform !ReadableStreamAddReadIntoRequest(stream,
|
||||
// readIntoRequest).
|
||||
ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest);
|
||||
|
||||
// Step 16, Perform
|
||||
// !ReadableByteStreamControllerCallPullIfNeeded(controller).
|
||||
// Step 19. Perform !ReadableByteStreamControllerCallPullIfNeeded(controller).
|
||||
ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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]].
|
||||
@ -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");
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ namespace mozilla::dom {
|
||||
class Promise;
|
||||
struct ReadIntoRequest;
|
||||
class ReadableStream;
|
||||
struct ReadableStreamBYOBReaderReadOptions;
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user