From db1985edcff5af11393b827dc5d61b69903fd911 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 13 Jul 2021 01:01:43 +0200 Subject: [PATCH 01/42] Add ReadableStreamBYOBReader.readFully() (first attempt) --- .../lib/ReadableStreamBYOBReader-impl.js | 25 +++++++ .../lib/ReadableStreamBYOBReader.webidl | 1 + .../lib/abstract-ops/readable-streams.js | 71 ++++++++++++++++--- 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 446846a45..9f4cfaa9c 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -36,6 +36,31 @@ class ReadableStreamBYOBReaderImpl { return promise; } + readFully(view) { + if (view.byteLength === 0) { + return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); + } + if (view.buffer.byteLength === 0) { + return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); + } + if (IsDetachedBuffer(view.buffer) === true) { + return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); + } + + if (this._stream === undefined) { + return promiseRejectedWith(readerLockException('readFully')); + } + + const promise = newPromise(); + const readFullyIntoRequest = { + chunkSteps: chunk => resolvePromise(promise, { value: chunk, done: false }), + closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), + errorSteps: e => rejectPromise(promise, e) + }; + aos.ReadableStreamBYOBReaderReadFully(this, view, readFullyIntoRequest); + return promise; + } + releaseLock() { if (this._stream === undefined) { return; diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index dfd3c25d8..bb2f1c03e 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -3,6 +3,7 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); + Promise readFully(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 285ac22e0..3ab6e4bce 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -42,6 +42,7 @@ Object.assign(exports, { ReadableByteStreamControllerRespondWithNewView, ReadableStreamAddReadRequest, ReadableStreamBYOBReaderRead, + ReadableStreamBYOBReaderReadFully, ReadableStreamBYOBReaderRelease, ReadableStreamCancel, ReadableStreamClose, @@ -720,11 +721,15 @@ function ReadableByteStreamTee(stream) { // Interfacing with controllers -function ReadableStreamAddReadIntoRequest(stream, readRequest) { +function ReadableStreamAddReadIntoRequest(stream, readRequest, addToFront = false) { assert(ReadableStreamBYOBReader.isImpl(stream._reader)); assert(stream._state === 'readable' || stream._state === 'closed'); - stream._reader._readIntoRequests.push(readRequest); + if (addToFront) { + stream._reader._readIntoRequests.unshift(readRequest); + } else { + stream._reader._readIntoRequests.push(readRequest); + } } function ReadableStreamAddReadRequest(stream, readRequest) { @@ -913,7 +918,7 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { +function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, addToFront = false) { const stream = reader._stream; assert(stream !== undefined); @@ -923,10 +928,50 @@ function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, addToFront); } } +function ReadableStreamBYOBReaderReadFully(reader, view, readFullyIntoRequest) { + const viewConstructor = view.constructor; + let elementSize = 1; + if (viewConstructor !== DataView) { + elementSize = view.constructor.BYTES_PER_ELEMENT; + } + + const byteOffset = view.byteOffset; + const byteLength = view.byteLength; + let bytesFilled = 0; + const readIntoRequest = { + chunkSteps: chunk => { + bytesFilled += chunk.byteLength; + if (bytesFilled === byteLength) { + const filledView = new viewConstructor(chunk.buffer, byteOffset, bytesFilled / elementSize); + readFullyIntoRequest.chunkSteps(filledView); + } else { + const remainderView = new viewConstructor( + chunk.buffer, + byteOffset + bytesFilled, + (byteLength - bytesFilled) / elementSize + ); + ReadableStreamBYOBReaderRead(reader, remainderView, readIntoRequest, true); + } + }, + closeSteps: chunk => { + if (chunk === undefined) { + readFullyIntoRequest.closeSteps(undefined); + return; + } + bytesFilled += chunk.byteLength; + const filledView = new viewConstructor(chunk.buffer, byteOffset, bytesFilled / elementSize); + readFullyIntoRequest.closeSteps(filledView); + }, + errorSteps: e => readFullyIntoRequest.errorSteps(e) + }; + + ReadableStreamBYOBReaderRead(reader, view, readIntoRequest); +} + function ReadableStreamBYOBReaderRelease(reader) { ReadableStreamReaderGenericRelease(reader); const e = new TypeError('Reader was released'); @@ -1563,7 +1608,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, addToFront = false) { const stream = controller._stream; let elementSize = 1; @@ -1593,13 +1638,17 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) }; if (controller._pendingPullIntos.length > 0) { - controller._pendingPullIntos.push(pullIntoDescriptor); + if (addToFront) { + controller._pendingPullIntos.unshift(pullIntoDescriptor); + } else { + controller._pendingPullIntos.push(pullIntoDescriptor); + } // No ReadableByteStreamControllerCallPullIfNeeded() call since: // - No change happens on desiredSize // - The source has already been notified of that there's at least 1 pending read(view) - ReadableStreamAddReadIntoRequest(stream, readIntoRequest); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest, addToFront); return; } @@ -1628,9 +1677,13 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) } } - controller._pendingPullIntos.push(pullIntoDescriptor); + if (addToFront) { + controller._pendingPullIntos.unshift(pullIntoDescriptor); + } else { + controller._pendingPullIntos.push(pullIntoDescriptor); + } - ReadableStreamAddReadIntoRequest(stream, readIntoRequest); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest, addToFront); ReadableByteStreamControllerCallPullIfNeeded(controller); } From 13d57946a8ef0aa3ad16af125c70b58209c7bbaa Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 15 Jul 2021 22:50:37 +0200 Subject: [PATCH 02/42] Revert "Add ReadableStreamBYOBReader.readFully() (first attempt)" This reverts commit ccdf1d120c5bdc279cc4fc8691655c0d4d54c41a. --- .../lib/ReadableStreamBYOBReader-impl.js | 25 ------- .../lib/ReadableStreamBYOBReader.webidl | 1 - .../lib/abstract-ops/readable-streams.js | 71 +++---------------- 3 files changed, 9 insertions(+), 88 deletions(-) diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 9f4cfaa9c..446846a45 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -36,31 +36,6 @@ class ReadableStreamBYOBReaderImpl { return promise; } - readFully(view) { - if (view.byteLength === 0) { - return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); - } - if (view.buffer.byteLength === 0) { - return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); - } - if (IsDetachedBuffer(view.buffer) === true) { - return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); - } - - if (this._stream === undefined) { - return promiseRejectedWith(readerLockException('readFully')); - } - - const promise = newPromise(); - const readFullyIntoRequest = { - chunkSteps: chunk => resolvePromise(promise, { value: chunk, done: false }), - closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), - errorSteps: e => rejectPromise(promise, e) - }; - aos.ReadableStreamBYOBReaderReadFully(this, view, readFullyIntoRequest); - return promise; - } - releaseLock() { if (this._stream === undefined) { return; diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index bb2f1c03e..dfd3c25d8 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -3,7 +3,6 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); - Promise readFully(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 3ab6e4bce..285ac22e0 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -42,7 +42,6 @@ Object.assign(exports, { ReadableByteStreamControllerRespondWithNewView, ReadableStreamAddReadRequest, ReadableStreamBYOBReaderRead, - ReadableStreamBYOBReaderReadFully, ReadableStreamBYOBReaderRelease, ReadableStreamCancel, ReadableStreamClose, @@ -721,15 +720,11 @@ function ReadableByteStreamTee(stream) { // Interfacing with controllers -function ReadableStreamAddReadIntoRequest(stream, readRequest, addToFront = false) { +function ReadableStreamAddReadIntoRequest(stream, readRequest) { assert(ReadableStreamBYOBReader.isImpl(stream._reader)); assert(stream._state === 'readable' || stream._state === 'closed'); - if (addToFront) { - stream._reader._readIntoRequests.unshift(readRequest); - } else { - stream._reader._readIntoRequests.push(readRequest); - } + stream._reader._readIntoRequests.push(readRequest); } function ReadableStreamAddReadRequest(stream, readRequest) { @@ -918,7 +913,7 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, addToFront = false) { +function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { const stream = reader._stream; assert(stream !== undefined); @@ -928,50 +923,10 @@ function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, addToFront if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, addToFront); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest); } } -function ReadableStreamBYOBReaderReadFully(reader, view, readFullyIntoRequest) { - const viewConstructor = view.constructor; - let elementSize = 1; - if (viewConstructor !== DataView) { - elementSize = view.constructor.BYTES_PER_ELEMENT; - } - - const byteOffset = view.byteOffset; - const byteLength = view.byteLength; - let bytesFilled = 0; - const readIntoRequest = { - chunkSteps: chunk => { - bytesFilled += chunk.byteLength; - if (bytesFilled === byteLength) { - const filledView = new viewConstructor(chunk.buffer, byteOffset, bytesFilled / elementSize); - readFullyIntoRequest.chunkSteps(filledView); - } else { - const remainderView = new viewConstructor( - chunk.buffer, - byteOffset + bytesFilled, - (byteLength - bytesFilled) / elementSize - ); - ReadableStreamBYOBReaderRead(reader, remainderView, readIntoRequest, true); - } - }, - closeSteps: chunk => { - if (chunk === undefined) { - readFullyIntoRequest.closeSteps(undefined); - return; - } - bytesFilled += chunk.byteLength; - const filledView = new viewConstructor(chunk.buffer, byteOffset, bytesFilled / elementSize); - readFullyIntoRequest.closeSteps(filledView); - }, - errorSteps: e => readFullyIntoRequest.errorSteps(e) - }; - - ReadableStreamBYOBReaderRead(reader, view, readIntoRequest); -} - function ReadableStreamBYOBReaderRelease(reader) { ReadableStreamReaderGenericRelease(reader); const e = new TypeError('Reader was released'); @@ -1608,7 +1563,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, addToFront = false) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) { const stream = controller._stream; let elementSize = 1; @@ -1638,17 +1593,13 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, }; if (controller._pendingPullIntos.length > 0) { - if (addToFront) { - controller._pendingPullIntos.unshift(pullIntoDescriptor); - } else { - controller._pendingPullIntos.push(pullIntoDescriptor); - } + controller._pendingPullIntos.push(pullIntoDescriptor); // No ReadableByteStreamControllerCallPullIfNeeded() call since: // - No change happens on desiredSize // - The source has already been notified of that there's at least 1 pending read(view) - ReadableStreamAddReadIntoRequest(stream, readIntoRequest, addToFront); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest); return; } @@ -1677,13 +1628,9 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, } } - if (addToFront) { - controller._pendingPullIntos.unshift(pullIntoDescriptor); - } else { - controller._pendingPullIntos.push(pullIntoDescriptor); - } + controller._pendingPullIntos.push(pullIntoDescriptor); - ReadableStreamAddReadIntoRequest(stream, readIntoRequest, addToFront); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest); ReadableByteStreamControllerCallPullIfNeeded(controller); } From cce92e22460574f476382805fea08f527c9925aa Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 15 Jul 2021 22:46:11 +0200 Subject: [PATCH 03/42] Add ReadableStreamBYOBReader.readFully() --- .../lib/ReadableByteStreamController-impl.js | 3 +- .../lib/ReadableStreamBYOBReader-impl.js | 25 +++++++++++ .../lib/ReadableStreamBYOBReader.webidl | 1 + .../lib/abstract-ops/readable-streams.js | 45 +++++++++++++++---- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 66cbe2278..3e20186b1 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -89,7 +89,8 @@ exports.implementation = class ReadableByteStreamControllerImpl { bytesFilled: 0, elementSize: 1, viewConstructor: Uint8Array, - readerType: 'default' + readerType: 'default', + readFully: false }; this._pendingPullIntos.push(pullIntoDescriptor); diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 446846a45..f2bcc4681 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -36,6 +36,31 @@ class ReadableStreamBYOBReaderImpl { return promise; } + readFully(view) { + if (view.byteLength === 0) { + return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); + } + if (view.buffer.byteLength === 0) { + return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); + } + if (IsDetachedBuffer(view.buffer) === true) { + return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); + } + + if (this._stream === undefined) { + return promiseRejectedWith(readerLockException('readFully')); + } + + const promise = newPromise(); + const readIntoRequest = { + chunkSteps: chunk => resolvePromise(promise, { value: chunk, done: false }), + closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), + errorSteps: e => rejectPromise(promise, e) + }; + aos.ReadableStreamBYOBReaderReadFully(this, view, readIntoRequest); + return promise; + } + releaseLock() { if (this._stream === undefined) { return; diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index dfd3c25d8..bb2f1c03e 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -3,6 +3,7 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); + Promise readFully(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 285ac22e0..f199b531e 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -42,6 +42,7 @@ Object.assign(exports, { ReadableByteStreamControllerRespondWithNewView, ReadableStreamAddReadRequest, ReadableStreamBYOBReaderRead, + ReadableStreamBYOBReaderReadFully, ReadableStreamBYOBReaderRelease, ReadableStreamCancel, ReadableStreamClose, @@ -923,7 +924,21 @@ function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, false); + } +} + +function ReadableStreamBYOBReaderReadFully(reader, view, readIntoRequest) { + const stream = reader._stream; + + assert(stream !== undefined); + + stream._disturbed = true; + + if (stream._state === 'errored') { + readIntoRequest.errorSteps(stream._storedError); + } else { + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, true); } } @@ -1272,7 +1287,7 @@ function ReadableByteStreamControllerClose(controller) { if (controller._pendingPullIntos.length > 0) { const firstPendingPullInto = controller._pendingPullIntos[0]; - if (firstPendingPullInto.bytesFilled > 0) { + if (firstPendingPullInto.bytesFilled % firstPendingPullInto.elementSize !== 0) { const e = new TypeError('Insufficient bytes to fill elements in the given buffer'); ReadableByteStreamControllerError(controller, e); @@ -1290,7 +1305,10 @@ function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDe let done = false; if (stream._state === 'closed') { - assert(pullIntoDescriptor.bytesFilled === 0); + assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); + if (!pullIntoDescriptor.readFully) { + assert(pullIntoDescriptor.bytesFilled === 0); + } done = true; } @@ -1432,7 +1450,9 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let ready = false; if (maxAlignedBytes > currentAlignedBytes) { totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - ready = true; + if (!pullIntoDescriptor.readFully || maxAlignedBytes === pullIntoDescriptor.byteLength) { + ready = true; + } } const queue = controller._queue; @@ -1461,7 +1481,11 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, if (ready === false) { assert(controller._queueTotalSize === 0); assert(pullIntoDescriptor.bytesFilled > 0); - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); + if (pullIntoDescriptor.readFully) { + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); + } else { + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); + } } return ready; @@ -1563,7 +1587,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, readFully = false) { const stream = controller._stream; let elementSize = 1; @@ -1589,7 +1613,8 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) bytesFilled: 0, elementSize, viewConstructor: ctor, - readerType: 'byob' + readerType: 'byob', + readFully }; if (controller._pendingPullIntos.length > 0) { @@ -1660,7 +1685,7 @@ function ReadableByteStreamControllerRespond(controller, bytesWritten) { } function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - assert(firstDescriptor.bytesFilled === 0); + assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); if (firstDescriptor.readerType === 'none') { ReadableByteStreamControllerShiftPendingPullInto(controller); @@ -1690,6 +1715,10 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri return; } + if (pullIntoDescriptor.readFully && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { + return; + } + ReadableByteStreamControllerShiftPendingPullInto(controller); const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; From 0326e95cfa6e7ceae629634dad313f3257f058b9 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Jul 2021 01:01:21 +0200 Subject: [PATCH 04/42] Use dual asserts --- .../lib/abstract-ops/readable-streams.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index f199b531e..6983b628a 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1305,8 +1305,9 @@ function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDe let done = false; if (stream._state === 'closed') { - assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); - if (!pullIntoDescriptor.readFully) { + if (pullIntoDescriptor.readFully) { + assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); + } else { assert(pullIntoDescriptor.bytesFilled === 0); } done = true; @@ -1685,7 +1686,11 @@ function ReadableByteStreamControllerRespond(controller, bytesWritten) { } function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); + if (firstDescriptor.readFully) { + assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); + } else { + assert(firstDescriptor.bytesFilled === 0); + } if (firstDescriptor.readerType === 'none') { ReadableByteStreamControllerShiftPendingPullInto(controller); From 864e010113b25cd33beb0e83361c1e11eabda23d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Jul 2021 01:01:52 +0200 Subject: [PATCH 05/42] Remove unused default value --- reference-implementation/lib/abstract-ops/readable-streams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 6983b628a..c0128fca7 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1588,7 +1588,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, readFully = false) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, readFully) { const stream = controller._stream; let elementSize = 1; From 09a199b6f8b57c220a86540a44b13b363b3f1379 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Jul 2021 01:33:30 +0200 Subject: [PATCH 06/42] Explain why we keep the readFully() pull-into descriptor at the head of the queue --- .../lib/abstract-ops/readable-streams.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index c0128fca7..cd22b321c 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1451,6 +1451,9 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let ready = false; if (maxAlignedBytes > currentAlignedBytes) { totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + // If this is a descriptor from a readFully() request, and it is not yet fully filled, then we keep it + // at the head of the queue. It will then be re-used to construct the next BYOB request. + // Otherwise, we remove the descriptor from the queue as soon as we filled it with any (aligned) amount of bytes. if (!pullIntoDescriptor.readFully || maxAlignedBytes === pullIntoDescriptor.byteLength) { ready = true; } @@ -1721,6 +1724,8 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri } if (pullIntoDescriptor.readFully && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { + // If this is a descriptor from a readFully() request, and it is not yet fully filled, then we keep it + // at the head of the queue. It will then be re-used to construct the next BYOB request. return; } From 5730f082a91ee5ba4b676652d82f0d38844eeba2 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 21 Jul 2021 00:57:41 +0200 Subject: [PATCH 07/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 517e945bb..cd3e7c906 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 517e945bbfaf903f37a35c11700eb96662efbdd3 +Subproject commit cd3e7c90635e891accb3b644a287cf67af6beb26 From 8ab2bbc49d0c8dc695e5caeb69977e6e9d0fd11f Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 21 Jul 2021 14:51:16 +0200 Subject: [PATCH 08/42] Fix typos --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 764d152f5..2949b5b49 100644 --- a/index.bs +++ b/index.bs @@ -1378,7 +1378,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea
{ value, done } = await reader.{{ReadableStreamBYOBReader/read()|read}}(view)
-

Attempts to reads bytes into |view|, and returns a promise resolved with the result: +

Attempts to read bytes into |view|, and returns a promise resolved with the result:

  • If the chunk does become available, the promise will be fulfilled with an object of the form @@ -3371,7 +3371,7 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-fill-pull-into-descriptor-from-queue">ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(|controller|, |pullIntoDescriptor|) performs the following steps: - 1. Let |elementSize| be |pullIntoDescriptor|.\[[elementSize]]. + 1. Let |elementSize| be |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. 1. Let |currentAlignedBytes| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] − (|pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |elementSize|). 1. Let |maxBytesToCopy| be min(|controller|.[=ReadableByteStreamController/[[queueTotalSize]]=], From 78d271162c11233e1eee2f5acf56ffa9157d56ce Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 21 Jul 2021 15:14:13 +0200 Subject: [PATCH 09/42] Add spec text for readFully() --- index.bs | 116 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 12 deletions(-) diff --git a/index.bs b/index.bs index 2949b5b49..a485e526e 100644 --- a/index.bs +++ b/index.bs @@ -1314,6 +1314,7 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); + Promise readFully(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; @@ -1402,6 +1403,34 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

    If reading a chunk causes the queue to become empty, more data will be pulled from the [=underlying source=]. +

    { value, done } = await reader.{{ReadableStreamBYOBReader/readFully()|readFully}}(view) +
    +

    Attempts to read bytes into |view| until it is completely full, and returns a promise resolved + with the result: + +

      +
    • If enough bytes become available to fill |view|, the promise will be fulfilled with an + object of the form { value: theView, done: false }. In this case, + |view| will be [=ArrayBuffer/detached=] and no longer usable, but theView will be a + new view (of the same type) onto the same backing memory region, with the received bytes written + into it. + +
    • If the stream becomes closed before |view| is full, the promise will be fulfilled with an + object of the form { value: theView, done: true }. In this case, + |view| will be [=ArrayBuffer/detached=] and no longer usable, but theChunk will be a + new view (of the same type) onto the same backing memory region, with any received bytes written + into it. + +
    • If the reader is [=cancel a readable stream|canceled=], the promise will be fulfilled with + an object of the form { value: undefined, done: true }. In this case, + the backing memory region of |view| is discarded and not returned to the caller. + +
    • If the stream becomes errored, the promise will be rejected with the relevant error. +
    + +

    If filling the view causes the queue to become empty, more data will be pulled from the + [=underlying source=]. This process repeats until either |view| is full, or the stream is closed. +

    reader.{{ReadableStreamBYOBReader/releaseLock()|releaseLock}}()

    [=release a read lock|Releases the reader's lock=] on the corresponding stream. After the lock @@ -1451,6 +1480,34 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea 1. Return |promise|. +

    + The readFully(|view|) + method steps are: + + 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. + 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, return [=a promise rejected + with=] a {{TypeError}} exception. + 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return + [=a promise rejected with=] a {{TypeError}} exception. + 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected + with=] a {{TypeError}} exception. + 1. Let |promise| be [=a new promise=]. + 1. Let |readIntoRequest| be a new [=read-into request=] with the following [=struct/items=]: + : [=read-into request/chunk steps=], given |chunk| + :: + 1. [=Resolve=] |promise| with «[ "{{ReadableStreamReadResult/value}}" → |chunk|, + "{{ReadableStreamReadResult/done}}" → false ]». + : [=read-into request/close steps=], given |chunk| + :: + 1. [=Resolve=] |promise| with «[ "{{ReadableStreamReadResult/value}}" → |chunk|, + "{{ReadableStreamReadResult/done}}" → true ]». + : [=read-into request/error steps=], given |e| + :: + 1. [=Reject=] |promise| with |e|. + 1. Perform ! [$ReadableStreamBYOBReaderReadFully$]([=this=], |view|, |readIntoRequest|). + 1. Return |promise|. +
    +
    The releaseLock() method steps are: @@ -1784,6 +1841,8 @@ has the following [=struct/items=]: :: Either "`default`" or "`byob`", indicating what type of [=readable stream reader=] initiated this request, or "`none`" if the initiating [=readable stream reader|reader=] was [=release a read lock|released=] +: read fully +:: A boolean flag indicating whether this is a {{ReadableStreamBYOBReader/readFully()}} request.

    Methods and properties

    @@ -1903,8 +1962,9 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by |buffer|.\[[Value]], [=pull-into descriptor/buffer byte length=] |autoAllocateChunkSize|, [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte length=] |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into - descriptor/element size=] 1, [=pull-into descriptor/view constructor=] {{%Uint8Array%}}, and - [=pull-into descriptor/reader type=] "`default`". + descriptor/element size=] 1, [=pull-into descriptor/view constructor=] {{%Uint8Array%}}, + [=pull-into descriptor/reader type=] "`default`", and [=pull-into descriptor/read fully=] + false. 1. [=list/Append=] |pullIntoDescriptor| to [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=]. 1. Perform ! [$ReadableStreamAddReadRequest$](|stream|, |readRequest|). @@ -2857,7 +2917,21 @@ The following abstract operations support the implementation and manipulation of 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], - |view|, |readIntoRequest|). + |view|, |readIntoRequest|, false). +
    + +
    + ReadableStreamBYOBReaderReadFully(|reader|, |view|, + |readIntoRequest|) performs the following steps: + + 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. + 1. Assert: |stream| is not undefined. + 1. Set |stream|.[=ReadableStream/[[disturbed]]=] to true. + 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into + request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. + 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], + |view|, |readIntoRequest|, true).
    @@ -3205,7 +3279,8 @@ The following abstract operations support the implementation of the 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. Let |firstPendingPullInto| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If |firstPendingPullInto|'s [=pull-into descriptor/bytes filled=] > 0, + 1. If |firstPendingPullInto|'s [=pull-into descriptor/bytes filled=] + mod |firstPendingPullInto|'s [=pull-into descriptor/element size=] is not 0, 1. Let |e| be a new {{TypeError}} exception. 1. Perform ! [$ReadableByteStreamControllerError$](|controller|, |e|). 1. Throw |e|. @@ -3222,7 +3297,11 @@ The following abstract operations support the implementation of the 1. Assert: |pullIntoDescriptor|.[=pull-into descriptor/reader type=] is not "`none`". 1. Let |done| be false. 1. If |stream|.[=ReadableStream/[[state]]=] is "`closed`", - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. + 1. Otherwise, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. 1. Set |done| to true. 1. Let |filledView| be ! [$ReadableByteStreamControllerConvertPullIntoDescriptor$](|pullIntoDescriptor|). @@ -3385,7 +3464,9 @@ The following abstract operations support the implementation of the 1. If |maxAlignedBytes| > |currentAlignedBytes|, 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. - 1. Set |ready| to true. + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is false or + |maxAlignedBytes| is equal to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], + 1. Set |ready| to true. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. 1. [=While=] |totalBytesToCopyRemaining| > 0, 1. Let |headOfQueue| be |queue|[0]. @@ -3412,8 +3493,12 @@ The following abstract operations support the implementation of the 1. If |ready| is false, 1. Assert: |controller|.[=ReadableByteStreamController/[[queueTotalSize]]=] is 0. 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] > 0. - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < - |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < + |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. + 1. Otherwise, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < + |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. 1. Return |ready|.
    @@ -3532,7 +3617,7 @@ The following abstract operations support the implementation of the
    ReadableByteStreamControllerPullInto(|controller|, - |view|, |readIntoRequest|) performs the following steps: + |view|, |readIntoRequest|, |readFully|) performs the following steps: 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. Let |elementSize| be 1. @@ -3553,8 +3638,8 @@ The following abstract operations support the implementation of the |buffer|, [=pull-into descriptor/buffer byte length=] |buffer|.\[[ArrayBufferByteLength]], [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] - |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, and [=pull-into - descriptor/reader type=] "`byob`". + |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, [=pull-into + descriptor/reader type=] "`byob`", and [=pull-into descriptor/read fully=] |readFully|. 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. [=list/Append=] |pullIntoDescriptor| to |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=]. @@ -3610,7 +3695,11 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-closed-state">ReadableByteStreamControllerRespondInClosedState(|controller|, |firstDescriptor|) performs the following steps: - 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. + 1. If |firstDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] mod |firstDescriptor|'s + [=pull-into descriptor/element size=] is 0. + 1. Otherwise, + 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. 1. If |firstDescriptor|'s [=pull-into descriptor/reader type=] is "`none`", perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. @@ -3638,6 +3727,9 @@ The following abstract operations support the implementation of the 1. Return. 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/element size=], return. + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true and |pullIntoDescriptor|'s + [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s + [=pull-into descriptor/byte length=], return. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |remainderSize| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. From 101fa7f589ef949045af6b605ec22f2936d5efac Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 21 Jul 2021 15:14:44 +0200 Subject: [PATCH 10/42] Tweak note --- index.bs | 7 +++++++ .../lib/abstract-ops/readable-streams.js | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index a485e526e..b44d99643 100644 --- a/index.bs +++ b/index.bs @@ -3467,6 +3467,10 @@ The following abstract operations support the implementation of the 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is false or |maxAlignedBytes| is equal to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], 1. Set |ready| to true. +

    A descriptor for a {{ReadableStreamBYOBReader/readFully()}} request + that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] + can keep filling it. Otherwise, we remove the descriptor from the queue as soon as we filled + it with any (aligned) amount of bytes. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. 1. [=While=] |totalBytesToCopyRemaining| > 0, 1. Let |headOfQueue| be |queue|[0]. @@ -3730,6 +3734,9 @@ The following abstract operations support the implementation of the 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true and |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], return. +

    A descriptor for a {{ReadableStreamBYOBReader/readFully()}} request + that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] + can keep filling it. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |remainderSize| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index cd22b321c..4fa34b924 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1451,8 +1451,8 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let ready = false; if (maxAlignedBytes > currentAlignedBytes) { totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - // If this is a descriptor from a readFully() request, and it is not yet fully filled, then we keep it - // at the head of the queue. It will then be re-used to construct the next BYOB request. + // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, + // so the underlying source can keep filling it. // Otherwise, we remove the descriptor from the queue as soon as we filled it with any (aligned) amount of bytes. if (!pullIntoDescriptor.readFully || maxAlignedBytes === pullIntoDescriptor.byteLength) { ready = true; @@ -1724,8 +1724,8 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri } if (pullIntoDescriptor.readFully && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { - // If this is a descriptor from a readFully() request, and it is not yet fully filled, then we keep it - // at the head of the queue. It will then be re-used to construct the next BYOB request. + // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, + // so the underlying source can keep filling it. return; } From 405cfb178e631ecd999da91f5252ec166b047abd Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 21 Jul 2021 17:15:14 +0200 Subject: [PATCH 11/42] Add note about readFully() in readInto() example --- index.bs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index b44d99643..7cecd791e 100644 --- a/index.bs +++ b/index.bs @@ -447,7 +447,7 @@ particularly important for the data structure described in [[#queue-with-sizes]] let offset = 0; while (offset < buffer.byteLength) { - const {value: view, done} = + const { value: view, done } = await reader.read(new Uint8Array(buffer, offset, buffer.byteLength - offset)); buffer = view.buffer; if (done) { @@ -467,6 +467,15 @@ particularly important for the data structure described in [[#queue-with-sizes]] new {{Uint8Array}}, with that {{ArrayBuffer}} object as its buffer property, the offset that bytes were written to as its byteOffset property, and the number of bytes that were written as its byteLength property. + + Note that this example is mostly educational. For practical purposes, + {{ReadableStreamBYOBReader/readFully()}} provides an easier and more direct way to read an exact + number of bytes: +

    + const reader = readableStream.getReader({ mode: "byob" }); + const { value: view, done } = await reader.readFully(new Uint8Array(1024)); + console.log("The first 1024 bytes: ", view); +

    The {{ReadableStream}} class

    From 345eb4082801feb36a7962d4ecaaaebbecb88f3f Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 23 Jul 2021 01:01:12 +0200 Subject: [PATCH 12/42] Always copy all queued bytes if readFully descriptor is not yet full --- index.bs | 19 +++++++++++-------- .../lib/abstract-ops/readable-streams.js | 14 +++++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 7cecd791e..d67fed7d4 100644 --- a/index.bs +++ b/index.bs @@ -3467,19 +3467,22 @@ The following abstract operations support the implementation of the descriptor/bytes filled=]). 1. Let |maxBytesFilled| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + |maxBytesToCopy|. - 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |elementSize|). 1. Let |totalBytesToCopyRemaining| be |maxBytesToCopy|. 1. Let |ready| be false. - 1. If |maxAlignedBytes| > |currentAlignedBytes|, - 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into - descriptor/bytes filled=]. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is false or - |maxAlignedBytes| is equal to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. If |maxBytesFilled| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], + 1. Set |totalBytesToCopyRemaining| to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=] + − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Set |ready| to true.

    A descriptor for a {{ReadableStreamBYOBReader/readFully()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] - can keep filling it. Otherwise, we remove the descriptor from the queue as soon as we filled - it with any (aligned) amount of bytes. + can keep filling it. + 1. Otherwise, + 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |elementSize|). + 1. If |maxAlignedBytes| > |currentAlignedBytes|, + 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into + descriptor/bytes filled=]. + 1. Set |ready| to true. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. 1. [=While=] |totalBytesToCopyRemaining| > 0, 1. Let |headOfQueue| be |queue|[0]. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 4fa34b924..05087b965 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1445,16 +1445,20 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, const maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; - const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; - if (maxAlignedBytes > currentAlignedBytes) { - totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + if (pullIntoDescriptor.readFully) { // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, // so the underlying source can keep filling it. - // Otherwise, we remove the descriptor from the queue as soon as we filled it with any (aligned) amount of bytes. - if (!pullIntoDescriptor.readFully || maxAlignedBytes === pullIntoDescriptor.byteLength) { + if (maxBytesFilled >= pullIntoDescriptor.byteLength) { + totalBytesToCopyRemaining = pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled; + ready = true; + } + } else { + const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; + if (maxAlignedBytes > currentAlignedBytes) { + totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; ready = true; } } From 3201762e8735e9669bb31e65326a8ecee8a8f126 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 23 Jul 2021 01:03:52 +0200 Subject: [PATCH 13/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index cd3e7c906..8ab7ac858 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit cd3e7c90635e891accb3b644a287cf67af6beb26 +Subproject commit 8ab7ac85865806d4bc0bd9bcd56be1088cb503f5 From b7c89fbdcf35829e4ff31f001ecf5207742fe680 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 23 Jul 2021 01:36:10 +0200 Subject: [PATCH 14/42] Simplify --- index.bs | 12 +++++++----- .../lib/abstract-ops/readable-streams.js | 10 ++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/index.bs b/index.bs index d67fed7d4..d98b23a6a 100644 --- a/index.bs +++ b/index.bs @@ -3459,9 +3459,6 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-fill-pull-into-descriptor-from-queue">ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(|controller|, |pullIntoDescriptor|) performs the following steps: - 1. Let |elementSize| be |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. - 1. Let |currentAlignedBytes| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] − - (|pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |elementSize|). 1. Let |maxBytesToCopy| be min(|controller|.[=ReadableByteStreamController/[[queueTotalSize]]=], |pullIntoDescriptor|'s [=pull-into descriptor/byte length=] − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]). @@ -3470,6 +3467,8 @@ The following abstract operations support the implementation of the 1. Let |totalBytesToCopyRemaining| be |maxBytesToCopy|. 1. Let |ready| be false. 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s + [=pull-into descriptor/byte length=]. 1. If |maxBytesFilled| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], 1. Set |totalBytesToCopyRemaining| to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=] − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. @@ -3478,8 +3477,11 @@ The following abstract operations support the implementation of the that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Otherwise, - 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |elementSize|). - 1. If |maxAlignedBytes| > |currentAlignedBytes|, + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s + [=pull-into descriptor/element size=]. + 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |pullIntoDescriptor|'s + [=pull-into descriptor/element size=]). + 1. If |maxAlignedBytes| > 0, 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Set |ready| to true. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 05087b965..239e2c2cf 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1438,10 +1438,6 @@ function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size } function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) { - const elementSize = pullIntoDescriptor.elementSize; - - const currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize; - const maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; @@ -1449,6 +1445,7 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; if (pullIntoDescriptor.readFully) { + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, // so the underlying source can keep filling it. if (maxBytesFilled >= pullIntoDescriptor.byteLength) { @@ -1456,8 +1453,9 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, ready = true; } } else { - const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; - if (maxAlignedBytes > currentAlignedBytes) { + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); + const maxAlignedBytes = maxBytesFilled - maxBytesFilled % pullIntoDescriptor.elementSize; + if (maxAlignedBytes > 0) { totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; ready = true; } From 9725a708aa8eddbb7226f93b84eb40886711cc67 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sun, 1 Aug 2021 14:36:16 +0200 Subject: [PATCH 15/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 8ab7ac858..ba6d376b3 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 8ab7ac85865806d4bc0bd9bcd56be1088cb503f5 +Subproject commit ba6d376b3826d758337a81f6c6ed94e6be41bd5f From d3bc4712b50a6469d5d50fb6492c3156154fb60f Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 19 Aug 2021 22:11:52 +0200 Subject: [PATCH 16/42] Replace "theChunk" and "theView" with "newView" --- index.bs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index d98b23a6a..98f7a94fa 100644 --- a/index.bs +++ b/index.bs @@ -1392,13 +1392,13 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

    • If the chunk does become available, the promise will be fulfilled with an object of the form - { value: theChunk, done: false }. In this case, |view| will be - [=ArrayBuffer/detached=] and no longer usable, but theChunk will be a new view (of + { value: newView, done: false }. In this case, |view| will be + [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with the chunk's data written into it.
    • If the stream becomes closed, the promise will be fulfilled with an object of the form - { value: theChunk, done: true }. In this case, |view| will be - [=ArrayBuffer/detached=] and no longer usable, but theChunk will be a new view (of + { value: newView, done: true }. In this case, |view| will be + [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with no modifications, to ensure the memory is returned to the caller. @@ -1419,14 +1419,14 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea
      • If enough bytes become available to fill |view|, the promise will be fulfilled with an - object of the form { value: theView, done: false }. In this case, - |view| will be [=ArrayBuffer/detached=] and no longer usable, but theView will be a + object of the form { value: newView, done: false }. In this case, + |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with the received bytes written into it.
      • If the stream becomes closed before |view| is full, the promise will be fulfilled with an - object of the form { value: theView, done: true }. In this case, - |view| will be [=ArrayBuffer/detached=] and no longer usable, but theChunk will be a + object of the form { value: newView, done: true }. In this case, + |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with any received bytes written into it. From 0d968aa204dde4aa135ee2b9f46c012dde700107 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 19 Aug 2021 22:19:28 +0200 Subject: [PATCH 17/42] Fix extra space --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 98f7a94fa..ab004956c 100644 --- a/index.bs +++ b/index.bs @@ -1419,7 +1419,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea
        • If enough bytes become available to fill |view|, the promise will be fulfilled with an - object of the form { value: newView, done: false }. In this case, + object of the form { value: newView, done: false }. In this case, |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with the received bytes written into it. From e9efa23bad2dc6154ce551674211dde00b5c7356 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 19 Aug 2021 22:25:14 +0200 Subject: [PATCH 18/42] Explain newView.byteLength --- index.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index ab004956c..a22c4a970 100644 --- a/index.bs +++ b/index.bs @@ -1422,13 +1422,14 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea object of the form { value: newView, done: false }. In this case, |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with the received bytes written - into it. + into it. newView will be completely filled, so its byteLength will + equal |view|'s byteLength.
        • If the stream becomes closed before |view| is full, the promise will be fulfilled with an object of the form { value: newView, done: true }. In this case, |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with any received bytes written - into it. + into it. newView.byteLength will equal that number of received bytes.
        • If the reader is [=cancel a readable stream|canceled=], the promise will be fulfilled with an object of the form { value: undefined, done: true }. In this case, From c8a4dfcbc23508d634e7761f77b4e791d9af3a7e Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 19 Aug 2021 22:37:43 +0200 Subject: [PATCH 19/42] Rename readFully() to fill() --- index.bs | 40 +++++++++---------- .../lib/ReadableByteStreamController-impl.js | 2 +- .../lib/ReadableStreamBYOBReader-impl.js | 6 +-- .../lib/ReadableStreamBYOBReader.webidl | 2 +- .../lib/abstract-ops/readable-streams.js | 22 +++++----- reference-implementation/web-platform-tests | 2 +- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/index.bs b/index.bs index a22c4a970..348276285 100644 --- a/index.bs +++ b/index.bs @@ -469,11 +469,11 @@ particularly important for the data structure described in [[#queue-with-sizes]] bytes that were written as its byteLength property. Note that this example is mostly educational. For practical purposes, - {{ReadableStreamBYOBReader/readFully()}} provides an easier and more direct way to read an exact + {{ReadableStreamBYOBReader/fill()}} provides an easier and more direct way to read an exact number of bytes: const reader = readableStream.getReader({ mode: "byob" }); - const { value: view, done } = await reader.readFully(new Uint8Array(1024)); + const { value: view, done } = await reader.fill(new Uint8Array(1024)); console.log("The first 1024 bytes: ", view); @@ -1323,7 +1323,7 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); - Promise readFully(ArrayBufferView view); + Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; @@ -1412,7 +1412,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          If reading a chunk causes the queue to become empty, more data will be pulled from the [=underlying source=]. -

          { value, done } = await reader.{{ReadableStreamBYOBReader/readFully()|readFully}}(view) +
          { value, done } = await reader.{{ReadableStreamBYOBReader/fill()|fill}}(view)

          Attempts to read bytes into |view| until it is completely full, and returns a promise resolved with the result: @@ -1491,7 +1491,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          - The readFully(|view|) + The fill(|view|) method steps are: 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. @@ -1514,7 +1514,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea : [=read-into request/error steps=], given |e| :: 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderReadFully$]([=this=], |view|, |readIntoRequest|). + 1. Perform ! [$ReadableStreamBYOBReaderFill$]([=this=], |view|, |readIntoRequest|). 1. Return |promise|.
          @@ -1851,8 +1851,8 @@ has the following [=struct/items=]: :: Either "`default`" or "`byob`", indicating what type of [=readable stream reader=] initiated this request, or "`none`" if the initiating [=readable stream reader|reader=] was [=release a read lock|released=] -: read fully -:: A boolean flag indicating whether this is a {{ReadableStreamBYOBReader/readFully()}} request. +: fill +:: A boolean flag indicating whether this is a {{ReadableStreamBYOBReader/fill()}} request.

          Methods and properties

          @@ -1973,7 +1973,7 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte length=] |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] 1, [=pull-into descriptor/view constructor=] {{%Uint8Array%}}, - [=pull-into descriptor/reader type=] "`default`", and [=pull-into descriptor/read fully=] + [=pull-into descriptor/reader type=] "`default`", and [=pull-into descriptor/fill=] false. 1. [=list/Append=] |pullIntoDescriptor| to [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=]. @@ -2931,8 +2931,8 @@ The following abstract operations support the implementation and manipulation of
          - ReadableStreamBYOBReaderReadFully(|reader|, |view|, + ReadableStreamBYOBReaderFill(|reader|, |view|, |readIntoRequest|) performs the following steps: 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. @@ -3307,7 +3307,7 @@ The following abstract operations support the implementation of the 1. Assert: |pullIntoDescriptor|.[=pull-into descriptor/reader type=] is not "`none`". 1. Let |done| be false. 1. If |stream|.[=ReadableStream/[[state]]=] is "`closed`", - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. 1. Otherwise, @@ -3467,14 +3467,14 @@ The following abstract operations support the implementation of the |maxBytesToCopy|. 1. Let |totalBytesToCopyRemaining| be |maxBytesToCopy|. 1. Let |ready| be false. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. 1. If |maxBytesFilled| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], 1. Set |totalBytesToCopyRemaining| to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=] − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Set |ready| to true. -

          A descriptor for a {{ReadableStreamBYOBReader/readFully()}} request +

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Otherwise, @@ -3512,7 +3512,7 @@ The following abstract operations support the implementation of the 1. If |ready| is false, 1. Assert: |controller|.[=ReadableByteStreamController/[[queueTotalSize]]=] is 0. 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] > 0. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. 1. Otherwise, @@ -3636,7 +3636,7 @@ The following abstract operations support the implementation of the

          ReadableByteStreamControllerPullInto(|controller|, - |view|, |readIntoRequest|, |readFully|) performs the following steps: + |view|, |readIntoRequest|, |fill|) performs the following steps: 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. Let |elementSize| be 1. @@ -3658,7 +3658,7 @@ The following abstract operations support the implementation of the [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, [=pull-into - descriptor/reader type=] "`byob`", and [=pull-into descriptor/read fully=] |readFully|. + descriptor/reader type=] "`byob`", and [=pull-into descriptor/fill=] |fill|. 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. [=list/Append=] |pullIntoDescriptor| to |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=]. @@ -3714,7 +3714,7 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-closed-state">ReadableByteStreamControllerRespondInClosedState(|controller|, |firstDescriptor|) performs the following steps: - 1. If |firstDescriptor|'s [=pull-into descriptor/read fully=] is true, + 1. If |firstDescriptor|'s [=pull-into descriptor/fill=] is true, 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] mod |firstDescriptor|'s [=pull-into descriptor/element size=] is 0. 1. Otherwise, @@ -3746,10 +3746,10 @@ The following abstract operations support the implementation of the 1. Return. 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/element size=], return. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/read fully=] is true and |pullIntoDescriptor|'s + 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true and |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], return. -

          A descriptor for a {{ReadableStreamBYOBReader/readFully()}} request +

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 3e20186b1..50fd8d598 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -90,7 +90,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { elementSize: 1, viewConstructor: Uint8Array, readerType: 'default', - readFully: false + fill: false }; this._pendingPullIntos.push(pullIntoDescriptor); diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index f2bcc4681..3122f89cc 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -36,7 +36,7 @@ class ReadableStreamBYOBReaderImpl { return promise; } - readFully(view) { + fill(view) { if (view.byteLength === 0) { return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); } @@ -48,7 +48,7 @@ class ReadableStreamBYOBReaderImpl { } if (this._stream === undefined) { - return promiseRejectedWith(readerLockException('readFully')); + return promiseRejectedWith(readerLockException('fill')); } const promise = newPromise(); @@ -57,7 +57,7 @@ class ReadableStreamBYOBReaderImpl { closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), errorSteps: e => rejectPromise(promise, e) }; - aos.ReadableStreamBYOBReaderReadFully(this, view, readIntoRequest); + aos.ReadableStreamBYOBReaderFill(this, view, readIntoRequest); return promise; } diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index bb2f1c03e..85048b847 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -3,7 +3,7 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view); - Promise readFully(ArrayBufferView view); + Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 239e2c2cf..625a6045d 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -41,8 +41,8 @@ Object.assign(exports, { ReadableByteStreamControllerRespond, ReadableByteStreamControllerRespondWithNewView, ReadableStreamAddReadRequest, + ReadableStreamBYOBReaderFill, ReadableStreamBYOBReaderRead, - ReadableStreamBYOBReaderReadFully, ReadableStreamBYOBReaderRelease, ReadableStreamCancel, ReadableStreamClose, @@ -928,7 +928,7 @@ function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { } } -function ReadableStreamBYOBReaderReadFully(reader, view, readIntoRequest) { +function ReadableStreamBYOBReaderFill(reader, view, readIntoRequest) { const stream = reader._stream; assert(stream !== undefined); @@ -1305,7 +1305,7 @@ function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDe let done = false; if (stream._state === 'closed') { - if (pullIntoDescriptor.readFully) { + if (pullIntoDescriptor.fill) { assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); } else { assert(pullIntoDescriptor.bytesFilled === 0); @@ -1444,9 +1444,9 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; - if (pullIntoDescriptor.readFully) { + if (pullIntoDescriptor.fill) { assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); - // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, + // A descriptor for a fill() request that is not yet completely filled will stay at the head of the queue, // so the underlying source can keep filling it. if (maxBytesFilled >= pullIntoDescriptor.byteLength) { totalBytesToCopyRemaining = pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled; @@ -1487,7 +1487,7 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, if (ready === false) { assert(controller._queueTotalSize === 0); assert(pullIntoDescriptor.bytesFilled > 0); - if (pullIntoDescriptor.readFully) { + if (pullIntoDescriptor.fill) { assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); } else { assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); @@ -1593,7 +1593,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, readFully) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, fill) { const stream = controller._stream; let elementSize = 1; @@ -1620,7 +1620,7 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, elementSize, viewConstructor: ctor, readerType: 'byob', - readFully + fill }; if (controller._pendingPullIntos.length > 0) { @@ -1691,7 +1691,7 @@ function ReadableByteStreamControllerRespond(controller, bytesWritten) { } function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - if (firstDescriptor.readFully) { + if (firstDescriptor.fill) { assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); } else { assert(firstDescriptor.bytesFilled === 0); @@ -1725,8 +1725,8 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri return; } - if (pullIntoDescriptor.readFully && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { - // A descriptor for a readFully() request that is not yet completely filled will stay at the head of the queue, + if (pullIntoDescriptor.fill && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { + // A descriptor for a fill() request that is not yet completely filled will stay at the head of the queue, // so the underlying source can keep filling it. return; } diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index ba6d376b3..53c7844c1 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit ba6d376b3826d758337a81f6c6ed94e6be41bd5f +Subproject commit 53c7844c1ed722b90cbcf363f5c34183f28c3d5f From 51dc85b2aff7fe5c2e1c4458871df0487fa29893 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 19 Aug 2021 23:45:11 +0200 Subject: [PATCH 20/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 53c7844c1..87607b350 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 53c7844c1ed722b90cbcf363f5c34183f28c3d5f +Subproject commit 87607b350271e7dbac8d36fce7bdb5a74d6ed884 From e6b12188ef4ce89e2433b245ff9aef107db82852 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 14 Oct 2021 00:57:11 +0200 Subject: [PATCH 21/42] Generalize fill(view) --- .../lib/ReadableByteStreamController-impl.js | 2 +- .../lib/ReadableStreamBYOBReader-impl.js | 2 +- .../lib/abstract-ops/readable-streams.js | 79 ++++++------------- 3 files changed, 27 insertions(+), 56 deletions(-) diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 50fd8d598..7a8c2639f 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -90,7 +90,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { elementSize: 1, viewConstructor: Uint8Array, readerType: 'default', - fill: false + minimumFilled: 1 }; this._pendingPullIntos.push(pullIntoDescriptor); diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 3122f89cc..0fe3c730d 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -57,7 +57,7 @@ class ReadableStreamBYOBReaderImpl { closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), errorSteps: e => rejectPromise(promise, e) }; - aos.ReadableStreamBYOBReaderFill(this, view, readIntoRequest); + aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, view.byteLength); return promise; } diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 625a6045d..597c50a55 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -41,7 +41,6 @@ Object.assign(exports, { ReadableByteStreamControllerRespond, ReadableByteStreamControllerRespondWithNewView, ReadableStreamAddReadRequest, - ReadableStreamBYOBReaderFill, ReadableStreamBYOBReaderRead, ReadableStreamBYOBReaderRelease, ReadableStreamCancel, @@ -914,31 +913,25 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { +function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, minimumFilled) { const stream = reader._stream; assert(stream !== undefined); stream._disturbed = true; - if (stream._state === 'errored') { - readIntoRequest.errorSteps(stream._storedError); - } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, false); + if (minimumFilled === undefined) { + let elementSize = 1; + if (view.constructor !== DataView) { + elementSize = view.constructor.BYTES_PER_ELEMENT; + } + minimumFilled = elementSize; } -} - -function ReadableStreamBYOBReaderFill(reader, view, readIntoRequest) { - const stream = reader._stream; - - assert(stream !== undefined); - - stream._disturbed = true; if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, true); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, minimumFilled); } } @@ -1305,11 +1298,7 @@ function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDe let done = false; if (stream._state === 'closed') { - if (pullIntoDescriptor.fill) { - assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); - } else { - assert(pullIntoDescriptor.bytesFilled === 0); - } + assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); done = true; } @@ -1444,21 +1433,13 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; - if (pullIntoDescriptor.fill) { - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); - // A descriptor for a fill() request that is not yet completely filled will stay at the head of the queue, - // so the underlying source can keep filling it. - if (maxBytesFilled >= pullIntoDescriptor.byteLength) { - totalBytesToCopyRemaining = pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled; - ready = true; - } - } else { - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); - const maxAlignedBytes = maxBytesFilled - maxBytesFilled % pullIntoDescriptor.elementSize; - if (maxAlignedBytes > 0) { - totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - ready = true; - } + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled); + const maxAlignedBytes = maxBytesFilled - maxBytesFilled % pullIntoDescriptor.elementSize; + // A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head + // of the queue, so the underlying source can keep filling it. + if (maxAlignedBytes >= pullIntoDescriptor.minimumFilled) { + totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + ready = true; } const queue = controller._queue; @@ -1487,11 +1468,7 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, if (ready === false) { assert(controller._queueTotalSize === 0); assert(pullIntoDescriptor.bytesFilled > 0); - if (pullIntoDescriptor.fill) { - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength); - } else { - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); - } + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled); } return ready; @@ -1593,13 +1570,15 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, fill) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, minimumFilled) { const stream = controller._stream; let elementSize = 1; if (view.constructor !== DataView) { elementSize = view.constructor.BYTES_PER_ELEMENT; } + assert(minimumFilled >= elementSize && minimumFilled <= view.byteLength); + assert(minimumFilled % elementSize === 0); const ctor = view.constructor; @@ -1620,7 +1599,7 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, elementSize, viewConstructor: ctor, readerType: 'byob', - fill + minimumFilled }; if (controller._pendingPullIntos.length > 0) { @@ -1691,11 +1670,7 @@ function ReadableByteStreamControllerRespond(controller, bytesWritten) { } function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - if (firstDescriptor.fill) { - assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); - } else { - assert(firstDescriptor.bytesFilled === 0); - } + assert(firstDescriptor.bytesFilled % firstDescriptor.elementSize === 0); if (firstDescriptor.readerType === 'none') { ReadableByteStreamControllerShiftPendingPullInto(controller); @@ -1721,13 +1696,9 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri return; } - if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { - return; - } - - if (pullIntoDescriptor.fill && pullIntoDescriptor.bytesFilled < pullIntoDescriptor.byteLength) { - // A descriptor for a fill() request that is not yet completely filled will stay at the head of the queue, - // so the underlying source can keep filling it. + if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled) { + // A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head + // of the queue, so the underlying source can keep filling it. return; } From 5d967c9be0042ee1fcb08f1c711c93f5b7734603 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 14 Oct 2021 23:12:16 +0200 Subject: [PATCH 22/42] Rename --- .../lib/ReadableByteStreamController-impl.js | 4 +-- .../lib/abstract-ops/readable-streams.js | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 7a8c2639f..eac1a028a 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -87,10 +87,10 @@ exports.implementation = class ReadableByteStreamControllerImpl { byteOffset: 0, byteLength: autoAllocateChunkSize, bytesFilled: 0, + minimumFill: 1, elementSize: 1, viewConstructor: Uint8Array, - readerType: 'default', - minimumFilled: 1 + readerType: 'default' }; this._pendingPullIntos.push(pullIntoDescriptor); diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 597c50a55..3ede1f17f 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -913,25 +913,25 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, minimumFilled) { +function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, minimumFill) { const stream = reader._stream; assert(stream !== undefined); stream._disturbed = true; - if (minimumFilled === undefined) { + if (minimumFill === undefined) { let elementSize = 1; if (view.constructor !== DataView) { elementSize = view.constructor.BYTES_PER_ELEMENT; } - minimumFilled = elementSize; + minimumFill = elementSize; } if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, minimumFilled); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, minimumFill); } } @@ -1433,11 +1433,11 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled); + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFill); const maxAlignedBytes = maxBytesFilled - maxBytesFilled % pullIntoDescriptor.elementSize; // A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head // of the queue, so the underlying source can keep filling it. - if (maxAlignedBytes >= pullIntoDescriptor.minimumFilled) { + if (maxAlignedBytes >= pullIntoDescriptor.minimumFill) { totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; ready = true; } @@ -1468,7 +1468,7 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, if (ready === false) { assert(controller._queueTotalSize === 0); assert(pullIntoDescriptor.bytesFilled > 0); - assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled); + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFill); } return ready; @@ -1570,15 +1570,16 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, minimumFilled) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, minimumFill) { const stream = controller._stream; let elementSize = 1; if (view.constructor !== DataView) { elementSize = view.constructor.BYTES_PER_ELEMENT; } - assert(minimumFilled >= elementSize && minimumFilled <= view.byteLength); - assert(minimumFilled % elementSize === 0); + + assert(minimumFill >= elementSize && minimumFill <= view.byteLength); + assert(minimumFill % elementSize === 0); const ctor = view.constructor; @@ -1596,10 +1597,10 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, byteOffset: view.byteOffset, byteLength: view.byteLength, bytesFilled: 0, + minimumFill, elementSize, viewConstructor: ctor, - readerType: 'byob', - minimumFilled + readerType: 'byob' }; if (controller._pendingPullIntos.length > 0) { @@ -1696,7 +1697,7 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri return; } - if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFilled) { + if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFill) { // A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head // of the queue, so the underlying source can keep filling it. return; From 511b3aee2ba396951ee5ef718ce5baee7763581b Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 Jan 2022 22:35:03 +0100 Subject: [PATCH 23/42] Update spec text --- index.bs | 105 +++++++++++++++++++++---------------------------------- 1 file changed, 40 insertions(+), 65 deletions(-) diff --git a/index.bs b/index.bs index 348276285..030d833b7 100644 --- a/index.bs +++ b/index.bs @@ -1514,7 +1514,8 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea : [=read-into request/error steps=], given |e| :: 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderFill$]([=this=], |view|, |readIntoRequest|). + 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, + |view|.\[[ByteLength]]). 1. Return |promise|.

          @@ -1840,6 +1841,10 @@ has the following [=struct/items=]: : bytes filled :: A nonnegative integer number of bytes that have been written into the [=pull-into descriptor/buffer=] so far +: minimum fill +:: A positive integer representing the minimum number of bytes that must be written into the + [=pull-into descriptor/buffer=] before the associated {{ReadableStreamBYOBReader/read()}} request + may be fulfilled. By default, this equals the [=pull-into descriptor/element size=]. : element size :: A positive integer representing the number of bytes that can be written into the [=pull-into descriptor/buffer=] at a time, using views of the type described by the [=pull-into @@ -1851,8 +1856,6 @@ has the following [=struct/items=]: :: Either "`default`" or "`byob`", indicating what type of [=readable stream reader=] initiated this request, or "`none`" if the initiating [=readable stream reader|reader=] was [=release a read lock|released=] -: fill -:: A boolean flag indicating whether this is a {{ReadableStreamBYOBReader/fill()}} request.

          Methods and properties

          @@ -1971,10 +1974,9 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] |buffer|.\[[Value]], [=pull-into descriptor/buffer byte length=] |autoAllocateChunkSize|, [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte length=] - |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into - descriptor/element size=] 1, [=pull-into descriptor/view constructor=] {{%Uint8Array%}}, - [=pull-into descriptor/reader type=] "`default`", and [=pull-into descriptor/fill=] - false. + |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/minimum + fill=] 1, [=pull-into descriptor/element size=] 1, [=pull-into descriptor/view constructor=] + {{%Uint8Array%}}, and [=pull-into descriptor/reader type=] "`default`". 1. [=list/Append=] |pullIntoDescriptor| to [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=]. 1. Perform ! [$ReadableStreamAddReadRequest$](|stream|, |readRequest|). @@ -2919,29 +2921,21 @@ The following abstract operations support the implementation and manipulation of
          ReadableStreamBYOBReaderRead(|reader|, |view|, - |readIntoRequest|) performs the following steps: - - 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. - 1. Assert: |stream| is not undefined. - 1. Set |stream|.[=ReadableStream/[[disturbed]]=] to true. - 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into - request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. - 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], - |view|, |readIntoRequest|, false). -
          - -
          - ReadableStreamBYOBReaderFill(|reader|, |view|, - |readIntoRequest|) performs the following steps: + |readIntoRequest|[, |minimumFill|]) performs the following steps: 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. 1. Assert: |stream| is not undefined. 1. Set |stream|.[=ReadableStream/[[disturbed]]=] to true. + 1. If |minimumFill| was not given, + 1. Let |elementSize| be 1. + 1. If |view| has a \[[TypedArrayName]] internal slot (i.e., it is not a {{DataView}}), set + |elementSize| to the element size specified in [=the typed array constructors table=] for + |view|.\[[TypedArrayName]]. + 1. Set |minimumFill| to |elementSize|. 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], - |view|, |readIntoRequest|, true). + |view|, |readIntoRequest|, |minimumFill|).
          @@ -3307,11 +3301,8 @@ The following abstract operations support the implementation of the 1. Assert: |pullIntoDescriptor|.[=pull-into descriptor/reader type=] is not "`none`". 1. Let |done| be false. 1. If |stream|.[=ReadableStream/[[state]]=] is "`closed`", - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] - mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. - 1. Otherwise, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. 1. Set |done| to true. 1. Let |filledView| be ! [$ReadableByteStreamControllerConvertPullIntoDescriptor$](|pullIntoDescriptor|). @@ -3467,25 +3458,17 @@ The following abstract operations support the implementation of the |maxBytesToCopy|. 1. Let |totalBytesToCopyRemaining| be |maxBytesToCopy|. 1. Let |ready| be false. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s - [=pull-into descriptor/byte length=]. - 1. If |maxBytesFilled| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], - 1. Set |totalBytesToCopyRemaining| to |pullIntoDescriptor|'s [=pull-into descriptor/byte length=] - − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. - 1. Set |ready| to true. -

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request - that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] - can keep filling it. - 1. Otherwise, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s - [=pull-into descriptor/element size=]. - 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |pullIntoDescriptor|'s - [=pull-into descriptor/element size=]). - 1. If |maxAlignedBytes| > 0, - 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s + [=pull-into descriptor/minimum fill=]. + 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |pullIntoDescriptor|'s + [=pull-into descriptor/element size=]). + 1. If |maxAlignedBytes| ≥ [=pull-into descriptor/minimum fill=], + 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. - 1. Set |ready| to true. + 1. Set |ready| to true. +

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request + that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] + can keep filling it. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. 1. [=While=] |totalBytesToCopyRemaining| > 0, 1. Let |headOfQueue| be |queue|[0]. @@ -3512,12 +3495,8 @@ The following abstract operations support the implementation of the 1. If |ready| is false, 1. Assert: |controller|.[=ReadableByteStreamController/[[queueTotalSize]]=] is 0. 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] > 0. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < - |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. - 1. Otherwise, - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < - |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < + |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=]. 1. Return |ready|.

          @@ -3636,7 +3615,7 @@ The following abstract operations support the implementation of the
          ReadableByteStreamControllerPullInto(|controller|, - |view|, |readIntoRequest|, |fill|) performs the following steps: + |view|, |readIntoRequest|, |minimumFill|) performs the following steps: 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. Let |elementSize| be 1. @@ -3646,6 +3625,8 @@ The following abstract operations support the implementation of the |view|.\[[TypedArrayName]]. 1. Set |ctor| to the constructor specified in [=the typed array constructors table=] for |view|.\[[TypedArrayName]]. + 1. Assert: |minimumFill| ≥ 0 and |minimumFill| ≤ |view|.\[[ByteLength]]. + 1. Assert: |minimumFill| mod |elementSize| is 0. 1. Let |byteOffset| be |view|.\[[ByteOffset]]. 1. Let |byteLength| be |view|.\[[ByteLength]]. 1. Let |bufferResult| be [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). @@ -3656,9 +3637,9 @@ The following abstract operations support the implementation of the 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] |buffer|, [=pull-into descriptor/buffer byte length=] |buffer|.\[[ArrayBufferByteLength]], [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] - |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] - |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, [=pull-into - descriptor/reader type=] "`byob`", and [=pull-into descriptor/fill=] |fill|. + |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/minimum fill=] + |minimumFill|, [=pull-into descriptor/element size=] |elementSize|, [=pull-into descriptor/view + constructor=] |ctor|, and [=pull-into descriptor/reader type=] "`byob`". 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. [=list/Append=] |pullIntoDescriptor| to |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=]. @@ -3714,11 +3695,8 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-closed-state">ReadableByteStreamControllerRespondInClosedState(|controller|, |firstDescriptor|) performs the following steps: - 1. If |firstDescriptor|'s [=pull-into descriptor/fill=] is true, - 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] mod |firstDescriptor|'s - [=pull-into descriptor/element size=] is 0. - 1. Otherwise, - 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. + 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] mod |firstDescriptor|'s + [=pull-into descriptor/element size=] is 0. 1. If |firstDescriptor|'s [=pull-into descriptor/reader type=] is "`none`", perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. @@ -3745,10 +3723,7 @@ The following abstract operations support the implementation of the 1. Perform ! [$ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$](|controller|). 1. Return. 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s - [=pull-into descriptor/element size=], return. - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/fill=] is true and |pullIntoDescriptor|'s - [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s - [=pull-into descriptor/byte length=], return. + [=pull-into descriptor/minimum fill=], return.

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. From 66dd27b99a7919a2f1551f69ea926664829be05b Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 14 Oct 2021 23:24:01 +0200 Subject: [PATCH 24/42] Add atLeast option to byobReader.read() --- index.bs | 23 +++++++++++++++--- .../lib/ReadableStreamBYOBReader-impl.js | 24 +++++++++++++++++-- .../lib/ReadableStreamBYOBReader.webidl | 6 ++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 030d833b7..9254a5cdc 100644 --- a/index.bs +++ b/index.bs @@ -1322,11 +1322,15 @@ The Web IDL definition for the {{ReadableStreamBYOBReader}} class is given as fo interface ReadableStreamBYOBReader { constructor(ReadableStream stream); - Promise read(ArrayBufferView view); + Promise read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {}); Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; + +dictionary ReadableStreamBYOBReaderReadOptions { + [EnforceRange] unsigned long long atLeast; +};

          Internal slots

          @@ -1463,7 +1467,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea
          - The read(|view|) + The read(|view|, |options|) method steps are: 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. @@ -1471,6 +1475,19 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea with=] a {{TypeError}} exception. 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return [=a promise rejected with=] a {{TypeError}} exception. + 1. Let |minimumFill| be undefined. + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] was given, + 1. If |view| has a \[[TypedArrayName]] internal slot, + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] > |view|.\[[ArrayLength]], + return [=a promise rejected with=] a {{RangeError}} exception. + 1. Let |elementSize| be the element size specified in [=the typed array constructors table=] for + |view|.\[[TypedArrayName]]. + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] * + |elementSize|. + 1. Otherwise (i.e., it is a {{DataView}}), + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] > |view|.\[[ByteLength]], + return [=a promise rejected with=] a {{RangeError}} exception. + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"]. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |promise| be [=a new promise=]. @@ -1486,7 +1503,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea : [=read-into request/error steps=], given |e| :: 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|). + 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, |minimumFill|). 1. Return |promise|.
          diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 0fe3c730d..3393551ce 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -11,7 +11,7 @@ class ReadableStreamBYOBReaderImpl { aos.SetUpReadableStreamBYOBReader(this, stream); } - read(view) { + read(view, options) { if (view.byteLength === 0) { return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); } @@ -22,6 +22,26 @@ class ReadableStreamBYOBReaderImpl { return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); } + let minimumFill; + if ('atLeast' in options) { + if (view.constructor !== DataView) { + if (options.atLeast > view.length) { + return promiseRejectedWith( + new RangeError('options.atLeast must be less than or equal to view\'s length') + ); + } + const elementSize = view.constructor.BYTES_PER_ELEMENT; + minimumFill = options.atLeast * elementSize; + } else { + if (options.atLeast > view.byteLength) { + return promiseRejectedWith( + new RangeError('options.atLeast must be less than or equal to view\'s byteLength') + ); + } + minimumFill = options.atLeast; + } + } + if (this._stream === undefined) { return promiseRejectedWith(readerLockException('read')); } @@ -32,7 +52,7 @@ class ReadableStreamBYOBReaderImpl { closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), errorSteps: e => rejectPromise(promise, e) }; - aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest); + aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, minimumFill); return promise; } diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index 85048b847..728a20420 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -2,8 +2,12 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); - Promise read(ArrayBufferView view); + Promise read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {}); Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; + +dictionary ReadableStreamBYOBReaderReadOptions { + [EnforceRange] unsigned long long atLeast; +}; From 3f1f12f8bb2ad5aaab7d2ee8a64d189d6c7891d3 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 Jan 2022 23:18:08 +0100 Subject: [PATCH 25/42] Remove fill(view) --- index.bs | 79 ++++--------------- .../lib/ReadableStreamBYOBReader-impl.js | 25 ------ .../lib/ReadableStreamBYOBReader.webidl | 1 - 3 files changed, 14 insertions(+), 91 deletions(-) diff --git a/index.bs b/index.bs index 9254a5cdc..840211aaa 100644 --- a/index.bs +++ b/index.bs @@ -468,12 +468,12 @@ particularly important for the data structure described in [[#queue-with-sizes]] offset that bytes were written to as its byteOffset property, and the number of bytes that were written as its byteLength property. - Note that this example is mostly educational. For practical purposes, - {{ReadableStreamBYOBReader/fill()}} provides an easier and more direct way to read an exact - number of bytes: + Note that this example is mostly educational. For practical purposes, the + {{ReadableStreamBYOBReaderReadOptions/atLeast}} option of {{ReadableStreamBYOBReader/read()}} + provides an easier and more direct way to read an exact number of bytes: const reader = readableStream.getReader({ mode: "byob" }); - const { value: view, done } = await reader.fill(new Uint8Array(1024)); + const { value: view, done } = await reader.read(new Uint8Array(1024), { atLeast: 1024 }); console.log("The first 1024 bytes: ", view);
          @@ -1323,7 +1323,6 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {}); - Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; @@ -1390,7 +1389,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          If the reader is [=active reader|active=], behaves the same |stream|.{{ReadableStream/cancel(reason)|cancel}}(reason). -

          { value, done } = await reader.{{ReadableStreamBYOBReader/read()|read}}(view) +
          { value, done } = await reader.{{ReadableStreamBYOBReader/read()|read}}(view[, { {{ReadableStreamBYOBReaderReadOptions/atLeast}} }])

          Attempts to read bytes into |view|, and returns a promise resolved with the result: @@ -1416,34 +1415,13 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          If reading a chunk causes the queue to become empty, more data will be pulled from the [=underlying source=]. -

          { value, done } = await reader.{{ReadableStreamBYOBReader/fill()|fill}}(view) -
          -

          Attempts to read bytes into |view| until it is completely full, and returns a promise resolved - with the result: - -

            -
          • If enough bytes become available to fill |view|, the promise will be fulfilled with an - object of the form { value: newView, done: false }. In this case, - |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a - new view (of the same type) onto the same backing memory region, with the received bytes written - into it. newView will be completely filled, so its byteLength will - equal |view|'s byteLength. - -
          • If the stream becomes closed before |view| is full, the promise will be fulfilled with an - object of the form { value: newView, done: true }. In this case, - |view| will be [=ArrayBuffer/detached=] and no longer usable, but newView will be a - new view (of the same type) onto the same backing memory region, with any received bytes written - into it. newView.byteLength will equal that number of received bytes. - -
          • If the reader is [=cancel a readable stream|canceled=], the promise will be fulfilled with - an object of the form { value: undefined, done: true }. In this case, - the backing memory region of |view| is discarded and not returned to the caller. - -
          • If the stream becomes errored, the promise will be rejected with the relevant error. -
          - -

          If filling the view causes the queue to become empty, more data will be pulled from the - [=underlying source=]. This process repeats until either |view| is full, or the stream is closed. +

          If {{ReadableStreamBYOBReaderReadOptions/atLeast}} is given, then the promise will only be + fulfilled as soon as at least the given number of elements are available. Here, the "number of + elements" is given by newView's length (for typed arrays) or + newView's byteLength (for {{DataView}}s). If the stream becomes closed, + then the promise is fulfilled with the remaining elements in the stream, which might be fewer than + the initially requested amount. If not given, then the promise resolves when at least one element + is available.

          reader.{{ReadableStreamBYOBReader/releaseLock()|releaseLock}}()
          @@ -1507,35 +1485,6 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea 1. Return |promise|. -
          - The fill(|view|) - method steps are: - - 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. - 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, return [=a promise rejected - with=] a {{TypeError}} exception. - 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return - [=a promise rejected with=] a {{TypeError}} exception. - 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected - with=] a {{TypeError}} exception. - 1. Let |promise| be [=a new promise=]. - 1. Let |readIntoRequest| be a new [=read-into request=] with the following [=struct/items=]: - : [=read-into request/chunk steps=], given |chunk| - :: - 1. [=Resolve=] |promise| with «[ "{{ReadableStreamReadResult/value}}" → |chunk|, - "{{ReadableStreamReadResult/done}}" → false ]». - : [=read-into request/close steps=], given |chunk| - :: - 1. [=Resolve=] |promise| with «[ "{{ReadableStreamReadResult/value}}" → |chunk|, - "{{ReadableStreamReadResult/done}}" → true ]». - : [=read-into request/error steps=], given |e| - :: - 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, - |view|.\[[ByteLength]]). - 1. Return |promise|. -
          -
          The releaseLock() method steps are: @@ -3483,7 +3432,7 @@ The following abstract operations support the implementation of the 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Set |ready| to true. -

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request +

          A descriptor for a {{ReadableStreamBYOBReader/read()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. @@ -3741,7 +3690,7 @@ The following abstract operations support the implementation of the 1. Return. 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=], return. -

          A descriptor for a {{ReadableStreamBYOBReader/fill()}} request +

          A descriptor for a {{ReadableStreamBYOBReader/read()}} request that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 3393551ce..19da3fdf9 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -56,31 +56,6 @@ class ReadableStreamBYOBReaderImpl { return promise; } - fill(view) { - if (view.byteLength === 0) { - return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); - } - if (view.buffer.byteLength === 0) { - return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); - } - if (IsDetachedBuffer(view.buffer) === true) { - return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); - } - - if (this._stream === undefined) { - return promiseRejectedWith(readerLockException('fill')); - } - - const promise = newPromise(); - const readIntoRequest = { - chunkSteps: chunk => resolvePromise(promise, { value: chunk, done: false }), - closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), - errorSteps: e => rejectPromise(promise, e) - }; - aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, view.byteLength); - return promise; - } - releaseLock() { if (this._stream === undefined) { return; diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index 728a20420..62003241a 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -3,7 +3,6 @@ interface ReadableStreamBYOBReader { constructor(ReadableStream stream); Promise read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {}); - Promise fill(ArrayBufferView view); undefined releaseLock(); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader; From d7ae44e185f0dda827af84bcf7d1f4ab30173b27 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 Jan 2022 23:26:57 +0100 Subject: [PATCH 26/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 87607b350..3deeddeae 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 87607b350271e7dbac8d36fce7bdb5a74d6ed884 +Subproject commit 3deeddeae1ef78625f25fe52b16b842d0af80aad From 1e1d6c6f2adf11e5804c9120f849a97b9ce16e18 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 Jan 2022 23:52:20 +0100 Subject: [PATCH 27/42] Fix note --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 840211aaa..a807c3f2d 100644 --- a/index.bs +++ b/index.bs @@ -3433,8 +3433,8 @@ The following abstract operations support the implementation of the descriptor/bytes filled=]. 1. Set |ready| to true.

          A descriptor for a {{ReadableStreamBYOBReader/read()}} request - that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] - can keep filling it. + that is not yet filled up to its minimum length will stay at the head of the queue, so the + [=underlying source=] can keep filling it. 1. Let |queue| be |controller|.[=ReadableByteStreamController/[[queue]]=]. 1. [=While=] |totalBytesToCopyRemaining| > 0, 1. Let |headOfQueue| be |queue|[0]. @@ -3691,8 +3691,8 @@ The following abstract operations support the implementation of the 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=], return.

          A descriptor for a {{ReadableStreamBYOBReader/read()}} request - that is not yet completely filled will stay at the head of the queue, so the [=underlying source=] - can keep filling it. + that is not yet filled up to its minimum length will stay at the head of the queue, so the + [=underlying source=] can keep filling it. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |remainderSize| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. From 15409a32d78424b441330d81069b5dd8439147a4 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 13 Apr 2022 00:19:34 +0200 Subject: [PATCH 28/42] Reject with a TypeError if atLeast is 0 --- index.bs | 2 ++ .../lib/ReadableStreamBYOBReader-impl.js | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/index.bs b/index.bs index a807c3f2d..604e6145e 100644 --- a/index.bs +++ b/index.bs @@ -1455,6 +1455,8 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea [=a promise rejected with=] a {{TypeError}} exception. 1. Let |minimumFill| be undefined. 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] was given, + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] is 0, return [=a promise + rejected with=] a {{TypeError}} exception. 1. If |view| has a \[[TypedArrayName]] internal slot, 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] > |view|.\[[ArrayLength]], return [=a promise rejected with=] a {{RangeError}} exception. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 19da3fdf9..137f349e4 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -24,6 +24,11 @@ class ReadableStreamBYOBReaderImpl { let minimumFill; if ('atLeast' in options) { + if (options.atLeast === 0) { + return promiseRejectedWith( + new TypeError('options.atLeast must be greater than 0') + ); + } if (view.constructor !== DataView) { if (options.atLeast > view.length) { return promiseRejectedWith( From 2b1147185627530807d3c0b14700bfec8f1af4d9 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 13 Apr 2022 00:29:52 +0200 Subject: [PATCH 29/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 3deeddeae..2e6cb148a 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 3deeddeae1ef78625f25fe52b16b842d0af80aad +Subproject commit 2e6cb148ab4ae60a31629486d586934556552684 From 1f3d73ff5fe4efa7e38c5d4cb72909b40404a865 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 28 Apr 2022 21:58:27 +0200 Subject: [PATCH 30/42] Rename "atLeast" to "min" --- index.bs | 24 +++++++++---------- .../lib/ReadableStreamBYOBReader-impl.js | 18 +++++++------- .../lib/ReadableStreamBYOBReader.webidl | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/index.bs b/index.bs index 604e6145e..36f598619 100644 --- a/index.bs +++ b/index.bs @@ -469,11 +469,11 @@ particularly important for the data structure described in [[#queue-with-sizes]] bytes that were written as its byteLength property. Note that this example is mostly educational. For practical purposes, the - {{ReadableStreamBYOBReaderReadOptions/atLeast}} option of {{ReadableStreamBYOBReader/read()}} + {{ReadableStreamBYOBReaderReadOptions/min}} option of {{ReadableStreamBYOBReader/read()}} provides an easier and more direct way to read an exact number of bytes:

          const reader = readableStream.getReader({ mode: "byob" }); - const { value: view, done } = await reader.read(new Uint8Array(1024), { atLeast: 1024 }); + const { value: view, done } = await reader.read(new Uint8Array(1024), { min: 1024 }); console.log("The first 1024 bytes: ", view);
          @@ -1328,7 +1328,7 @@ interface ReadableStreamBYOBReader { ReadableStreamBYOBReader includes ReadableStreamGenericReader; dictionary ReadableStreamBYOBReaderReadOptions { - [EnforceRange] unsigned long long atLeast; + [EnforceRange] unsigned long long min; }; @@ -1389,7 +1389,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          If the reader is [=active reader|active=], behaves the same |stream|.{{ReadableStream/cancel(reason)|cancel}}(reason). -

          { value, done } = await reader.{{ReadableStreamBYOBReader/read()|read}}(view[, { {{ReadableStreamBYOBReaderReadOptions/atLeast}} }]) +
          { value, done } = await reader.{{ReadableStreamBYOBReader/read()|read}}(view[, { {{ReadableStreamBYOBReaderReadOptions/min}} }])

          Attempts to read bytes into |view|, and returns a promise resolved with the result: @@ -1415,8 +1415,8 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea

          If reading a chunk causes the queue to become empty, more data will be pulled from the [=underlying source=]. -

          If {{ReadableStreamBYOBReaderReadOptions/atLeast}} is given, then the promise will only be - fulfilled as soon as at least the given number of elements are available. Here, the "number of +

          If {{ReadableStreamBYOBReaderReadOptions/min}} is given, then the promise will only be + fulfilled as soon as the given minimum number of elements are available. Here, the "number of elements" is given by newView's length (for typed arrays) or newView's byteLength (for {{DataView}}s). If the stream becomes closed, then the promise is fulfilled with the remaining elements in the stream, which might be fewer than @@ -1454,20 +1454,20 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |minimumFill| be undefined. - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] was given, - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] is 0, return [=a promise + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] was given, + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] is 0, return [=a promise rejected with=] a {{TypeError}} exception. 1. If |view| has a \[[TypedArrayName]] internal slot, - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] > |view|.\[[ArrayLength]], + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ArrayLength]], return [=a promise rejected with=] a {{RangeError}} exception. 1. Let |elementSize| be the element size specified in [=the typed array constructors table=] for |view|.\[[TypedArrayName]]. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] * + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] * |elementSize|. 1. Otherwise (i.e., it is a {{DataView}}), - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"] > |view|.\[[ByteLength]], + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ByteLength]], return [=a promise rejected with=] a {{RangeError}} exception. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/atLeast}}"]. + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |promise| be [=a new promise=]. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 137f349e4..c70c698c0 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -23,27 +23,27 @@ class ReadableStreamBYOBReaderImpl { } let minimumFill; - if ('atLeast' in options) { - if (options.atLeast === 0) { + if ('min' in options) { + if (options.min === 0) { return promiseRejectedWith( - new TypeError('options.atLeast must be greater than 0') + new TypeError('options.min must be greater than 0') ); } if (view.constructor !== DataView) { - if (options.atLeast > view.length) { + if (options.min > view.length) { return promiseRejectedWith( - new RangeError('options.atLeast must be less than or equal to view\'s length') + new RangeError('options.min must be less than or equal to view\'s length') ); } const elementSize = view.constructor.BYTES_PER_ELEMENT; - minimumFill = options.atLeast * elementSize; + minimumFill = options.min * elementSize; } else { - if (options.atLeast > view.byteLength) { + if (options.min > view.byteLength) { return promiseRejectedWith( - new RangeError('options.atLeast must be less than or equal to view\'s byteLength') + new RangeError('options.min must be less than or equal to view\'s byteLength') ); } - minimumFill = options.atLeast; + minimumFill = options.min; } } diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index 62003241a..5e03fc3f4 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -8,5 +8,5 @@ interface ReadableStreamBYOBReader { ReadableStreamBYOBReader includes ReadableStreamGenericReader; dictionary ReadableStreamBYOBReaderReadOptions { - [EnforceRange] unsigned long long atLeast; + [EnforceRange] unsigned long long min; }; From 3bc12831eccec89897a0365f92b809fe60336305 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 28 Apr 2022 22:01:46 +0200 Subject: [PATCH 31/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 2e6cb148a..07fc5ee46 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 2e6cb148ab4ae60a31629486d586934556552684 +Subproject commit 07fc5ee465e8dd5478c3d0fd3867269081263c7f From f1572e5e7a5e2fc6124de7f443827aefdbfc2a11 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 28 Apr 2022 22:35:54 +0200 Subject: [PATCH 32/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 07fc5ee46..e9fb8172b 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 07fc5ee465e8dd5478c3d0fd3867269081263c7f +Subproject commit e9fb8172b1c9cff1721961cc7a27e5534424229d From 78f7adcc393c84d3bf6704da5541c84a4b109f78 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 9 Jun 2023 17:08:46 +0200 Subject: [PATCH 33/42] Fix typo --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 36f598619..6759319c3 100644 --- a/index.bs +++ b/index.bs @@ -3430,7 +3430,7 @@ The following abstract operations support the implementation of the [=pull-into descriptor/minimum fill=]. 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=]). - 1. If |maxAlignedBytes| ≥ [=pull-into descriptor/minimum fill=], + 1. If |maxAlignedBytes| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=], 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Set |ready| to true. From 6f5196ab98dbdc04b2234fa69c6eb175410307cd Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 16 Sep 2023 11:38:16 +0200 Subject: [PATCH 34/42] Set ReadableStreamBYOBReaderReadOptions.min = 1 by default --- index.bs | 27 +++++++-------- .../lib/ReadableStreamBYOBReader-impl.js | 34 +++++++++---------- .../lib/ReadableStreamBYOBReader.webidl | 2 +- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/index.bs b/index.bs index 6759319c3..37bcc90b9 100644 --- a/index.bs +++ b/index.bs @@ -1328,7 +1328,7 @@ interface ReadableStreamBYOBReader { ReadableStreamBYOBReader includes ReadableStreamGenericReader; dictionary ReadableStreamBYOBReaderReadOptions { - [EnforceRange] unsigned long long min; + [EnforceRange] unsigned long long min = 1; }; @@ -1454,20 +1454,19 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |minimumFill| be undefined. - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] was given, - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] is 0, return [=a promise + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] is 0, return [=a promise rejected with=] a {{TypeError}} exception. - 1. If |view| has a \[[TypedArrayName]] internal slot, - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ArrayLength]], - return [=a promise rejected with=] a {{RangeError}} exception. - 1. Let |elementSize| be the element size specified in [=the typed array constructors table=] for - |view|.\[[TypedArrayName]]. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] * - |elementSize|. - 1. Otherwise (i.e., it is a {{DataView}}), - 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ByteLength]], - return [=a promise rejected with=] a {{RangeError}} exception. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]. + 1. If |view| has a \[[TypedArrayName]] internal slot, + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ArrayLength]], + return [=a promise rejected with=] a {{RangeError}} exception. + 1. Let |elementSize| be the element size specified in [=the typed array constructors table=] for + |view|.\[[TypedArrayName]]. + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] * + |elementSize|. + 1. Otherwise (i.e., it is a {{DataView}}), + 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ByteLength]], + return [=a promise rejected with=] a {{RangeError}} exception. + 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |promise| be [=a new promise=]. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index c70c698c0..6cc982929 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -23,28 +23,26 @@ class ReadableStreamBYOBReaderImpl { } let minimumFill; - if ('min' in options) { - if (options.min === 0) { + if (options.min === 0) { + return promiseRejectedWith( + new TypeError('options.min must be greater than 0') + ); + } + if (view.constructor !== DataView) { + if (options.min > view.length) { return promiseRejectedWith( - new TypeError('options.min must be greater than 0') + new RangeError('options.min must be less than or equal to view\'s length') ); } - if (view.constructor !== DataView) { - if (options.min > view.length) { - return promiseRejectedWith( - new RangeError('options.min must be less than or equal to view\'s length') - ); - } - const elementSize = view.constructor.BYTES_PER_ELEMENT; - minimumFill = options.min * elementSize; - } else { - if (options.min > view.byteLength) { - return promiseRejectedWith( - new RangeError('options.min must be less than or equal to view\'s byteLength') - ); - } - minimumFill = options.min; + const elementSize = view.constructor.BYTES_PER_ELEMENT; + minimumFill = options.min * elementSize; + } else { + if (options.min > view.byteLength) { + return promiseRejectedWith( + new RangeError('options.min must be less than or equal to view\'s byteLength') + ); } + minimumFill = options.min; } if (this._stream === undefined) { diff --git a/reference-implementation/lib/ReadableStreamBYOBReader.webidl b/reference-implementation/lib/ReadableStreamBYOBReader.webidl index 5e03fc3f4..6967c4311 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader.webidl +++ b/reference-implementation/lib/ReadableStreamBYOBReader.webidl @@ -8,5 +8,5 @@ interface ReadableStreamBYOBReader { ReadableStreamBYOBReader includes ReadableStreamGenericReader; dictionary ReadableStreamBYOBReaderReadOptions { - [EnforceRange] unsigned long long min; + [EnforceRange] unsigned long long min = 1; }; From 8f2e4a4a4d2ec97c8b83de3f2bf8450a42d7b9ef Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 16 Sep 2023 11:43:10 +0200 Subject: [PATCH 35/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index e9fb8172b..979fc6bbb 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit e9fb8172b1c9cff1721961cc7a27e5534424229d +Subproject commit 979fc6bbbf20615228867c4bfe3b505cad17fe3a From d17aecae99186634a8c6b169cc0d8458c73a2862 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 16 Sep 2023 12:54:09 +0200 Subject: [PATCH 36/42] Rename minimumFill to min in ReadableStreamBYOBReaderRead, and make required --- index.bs | 23 +++++-------------- .../lib/ReadableStreamBYOBReader-impl.js | 6 +---- .../lib/abstract-ops/readable-streams.js | 17 ++++---------- 3 files changed, 12 insertions(+), 34 deletions(-) diff --git a/index.bs b/index.bs index 37bcc90b9..52729a3f9 100644 --- a/index.bs +++ b/index.bs @@ -1453,20 +1453,14 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea with=] a {{TypeError}} exception. 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return [=a promise rejected with=] a {{TypeError}} exception. - 1. Let |minimumFill| be undefined. 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] is 0, return [=a promise rejected with=] a {{TypeError}} exception. 1. If |view| has a \[[TypedArrayName]] internal slot, 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ArrayLength]], return [=a promise rejected with=] a {{RangeError}} exception. - 1. Let |elementSize| be the element size specified in [=the typed array constructors table=] for - |view|.\[[TypedArrayName]]. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] * - |elementSize|. 1. Otherwise (i.e., it is a {{DataView}}), 1. If |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"] > |view|.\[[ByteLength]], return [=a promise rejected with=] a {{RangeError}} exception. - 1. Set |minimumFill| to |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |promise| be [=a new promise=]. @@ -1482,7 +1476,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea : [=read-into request/error steps=], given |e| :: 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, |minimumFill|). + 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]). 1. Return |promise|. @@ -2587,7 +2581,7 @@ create them does not matter. : [=read-into request/error steps=] :: 1. Set |reading| to false. - 1. Perform ! [$ReadableStreamBYOBReaderRead$](|reader|, |view|, |readIntoRequest|). + 1. Perform ! [$ReadableStreamBYOBReaderRead$](|reader|, |view|, |readIntoRequest|, 1). 1. Let |pull1Algorithm| be the following steps: 1. If |reading| is true, 1. Set |readAgainForBranch1| to true. @@ -2888,21 +2882,15 @@ The following abstract operations support the implementation and manipulation of

          ReadableStreamBYOBReaderRead(|reader|, |view|, - |readIntoRequest|[, |minimumFill|]) performs the following steps: + |readIntoRequest|, |min|) performs the following steps: 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. 1. Assert: |stream| is not undefined. 1. Set |stream|.[=ReadableStream/[[disturbed]]=] to true. - 1. If |minimumFill| was not given, - 1. Let |elementSize| be 1. - 1. If |view| has a \[[TypedArrayName]] internal slot (i.e., it is not a {{DataView}}), set - |elementSize| to the element size specified in [=the typed array constructors table=] for - |view|.\[[TypedArrayName]]. - 1. Set |minimumFill| to |elementSize|. 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], - |view|, |readIntoRequest|, |minimumFill|). + |view|, |readIntoRequest|, |min|).
          @@ -3582,7 +3570,7 @@ The following abstract operations support the implementation of the
          ReadableByteStreamControllerPullInto(|controller|, - |view|, |readIntoRequest|, |minimumFill|) performs the following steps: + |view|, |readIntoRequest|, |min|) performs the following steps: 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. Let |elementSize| be 1. @@ -3592,6 +3580,7 @@ The following abstract operations support the implementation of the |view|.\[[TypedArrayName]]. 1. Set |ctor| to the constructor specified in [=the typed array constructors table=] for |view|.\[[TypedArrayName]]. + 1. Let |minimumFill| be |min| * |elementSize|. 1. Assert: |minimumFill| ≥ 0 and |minimumFill| ≤ |view|.\[[ByteLength]]. 1. Assert: |minimumFill| mod |elementSize| is 0. 1. Let |byteOffset| be |view|.\[[ByteOffset]]. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 6cc982929..05546419a 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -22,7 +22,6 @@ class ReadableStreamBYOBReaderImpl { return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); } - let minimumFill; if (options.min === 0) { return promiseRejectedWith( new TypeError('options.min must be greater than 0') @@ -34,15 +33,12 @@ class ReadableStreamBYOBReaderImpl { new RangeError('options.min must be less than or equal to view\'s length') ); } - const elementSize = view.constructor.BYTES_PER_ELEMENT; - minimumFill = options.min * elementSize; } else { if (options.min > view.byteLength) { return promiseRejectedWith( new RangeError('options.min must be less than or equal to view\'s byteLength') ); } - minimumFill = options.min; } if (this._stream === undefined) { @@ -55,7 +51,7 @@ class ReadableStreamBYOBReaderImpl { closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), errorSteps: e => rejectPromise(promise, e) }; - aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, minimumFill); + aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, options.min); return promise; } diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 3ede1f17f..15d598b03 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -647,7 +647,7 @@ function ReadableByteStreamTee(stream) { reading = false; } }; - ReadableStreamBYOBReaderRead(reader, view, readIntoRequest); + ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, 1); } function pull1Algorithm() { @@ -913,25 +913,17 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, minimumFill) { +function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, min) { const stream = reader._stream; assert(stream !== undefined); stream._disturbed = true; - if (minimumFill === undefined) { - let elementSize = 1; - if (view.constructor !== DataView) { - elementSize = view.constructor.BYTES_PER_ELEMENT; - } - minimumFill = elementSize; - } - if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, minimumFill); + ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, min); } } @@ -1570,7 +1562,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, minimumFill) { +function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, min) { const stream = controller._stream; let elementSize = 1; @@ -1578,6 +1570,7 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, elementSize = view.constructor.BYTES_PER_ELEMENT; } + const minimumFill = min * elementSize; assert(minimumFill >= elementSize && minimumFill <= view.byteLength); assert(minimumFill % elementSize === 0); From e381f25014db461a8f3c81eacb1bf84588bf75de Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 16 Sep 2023 12:57:48 +0200 Subject: [PATCH 37/42] Move readIntoRequest to last argument --- index.bs | 12 ++++++------ .../lib/ReadableStreamBYOBReader-impl.js | 2 +- .../lib/abstract-ops/readable-streams.js | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/index.bs b/index.bs index 52729a3f9..67ca070b1 100644 --- a/index.bs +++ b/index.bs @@ -1476,7 +1476,7 @@ value: newViewOnSameMemory, done: true } for closed streams. If the strea : [=read-into request/error steps=], given |e| :: 1. [=Reject=] |promise| with |e|. - 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |readIntoRequest|, |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"]). + 1. Perform ! [$ReadableStreamBYOBReaderRead$]([=this=], |view|, |options|["{{ReadableStreamBYOBReaderReadOptions/min}}"], |readIntoRequest|). 1. Return |promise|.
          @@ -2581,7 +2581,7 @@ create them does not matter. : [=read-into request/error steps=] :: 1. Set |reading| to false. - 1. Perform ! [$ReadableStreamBYOBReaderRead$](|reader|, |view|, |readIntoRequest|, 1). + 1. Perform ! [$ReadableStreamBYOBReaderRead$](|reader|, |view|, 1, |readIntoRequest|). 1. Let |pull1Algorithm| be the following steps: 1. If |reading| is true, 1. Set |readAgainForBranch1| to true. @@ -2881,8 +2881,8 @@ The following abstract operations support the implementation and manipulation of
          ReadableStreamBYOBReaderRead(|reader|, |view|, - |readIntoRequest|, |min|) performs the following steps: + id="readable-stream-byob-reader-read">ReadableStreamBYOBReaderRead(|reader|, |view|, |min|, + |readIntoRequest|) performs the following steps: 1. Let |stream| be |reader|.[=ReadableStreamGenericReader/[[stream]]=]. 1. Assert: |stream| is not undefined. @@ -2890,7 +2890,7 @@ The following abstract operations support the implementation and manipulation of 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", perform |readIntoRequest|'s [=read-into request/error steps=] given |stream|.[=ReadableStream/[[storedError]]=]. 1. Otherwise, perform ! [$ReadableByteStreamControllerPullInto$](|stream|.[=ReadableStream/[[controller]]=], - |view|, |readIntoRequest|, |min|). + |view|, |min|, |readIntoRequest|).
          @@ -3570,7 +3570,7 @@ The following abstract operations support the implementation of the
          ReadableByteStreamControllerPullInto(|controller|, - |view|, |readIntoRequest|, |min|) performs the following steps: + |view|, |min|, |readIntoRequest|) performs the following steps: 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. Let |elementSize| be 1. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 05546419a..30023c817 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -51,7 +51,7 @@ class ReadableStreamBYOBReaderImpl { closeSteps: chunk => resolvePromise(promise, { value: chunk, done: true }), errorSteps: e => rejectPromise(promise, e) }; - aos.ReadableStreamBYOBReaderRead(this, view, readIntoRequest, options.min); + aos.ReadableStreamBYOBReaderRead(this, view, options.min, readIntoRequest); return promise; } diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 15d598b03..9d20ff705 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -647,7 +647,7 @@ function ReadableByteStreamTee(stream) { reading = false; } }; - ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, 1); + ReadableStreamBYOBReaderRead(reader, view, 1, readIntoRequest); } function pull1Algorithm() { @@ -913,7 +913,7 @@ function ReadableStreamReaderGenericRelease(reader) { reader._stream = undefined; } -function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, min) { +function ReadableStreamBYOBReaderRead(reader, view, min, readIntoRequest) { const stream = reader._stream; assert(stream !== undefined); @@ -923,7 +923,7 @@ function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest, min) { if (stream._state === 'errored') { readIntoRequest.errorSteps(stream._storedError); } else { - ReadableByteStreamControllerPullInto(stream._controller, view, readIntoRequest, min); + ReadableByteStreamControllerPullInto(stream._controller, view, min, readIntoRequest); } } @@ -1562,7 +1562,7 @@ function ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) { } } -function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest, min) { +function ReadableByteStreamControllerPullInto(controller, view, min, readIntoRequest) { const stream = controller._stream; let elementSize = 1; From c39be05137f47371b8b87d052c20d5e43497bfa3 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 16 Sep 2023 13:02:40 +0200 Subject: [PATCH 38/42] Fix lint error --- .../lib/ReadableStreamBYOBReader-impl.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 30023c817..954761162 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -33,12 +33,10 @@ class ReadableStreamBYOBReaderImpl { new RangeError('options.min must be less than or equal to view\'s length') ); } - } else { - if (options.min > view.byteLength) { - return promiseRejectedWith( - new RangeError('options.min must be less than or equal to view\'s byteLength') - ); - } + } else if (options.min > view.byteLength) { + return promiseRejectedWith( + new RangeError('options.min must be less than or equal to view\'s byteLength') + ); } if (this._stream === undefined) { From 9351f13c1f1f502dbd56e398579d9b28a6226de1 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 28 Sep 2023 14:26:25 +0900 Subject: [PATCH 39/42] Small improvements --- index.bs | 73 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 67ca070b1..3296b6da9 100644 --- a/index.bs +++ b/index.bs @@ -471,6 +471,7 @@ particularly important for the data structure described in [[#queue-with-sizes]] Note that this example is mostly educational. For practical purposes, the {{ReadableStreamBYOBReaderReadOptions/min}} option of {{ReadableStreamBYOBReader/read()}} provides an easier and more direct way to read an exact number of bytes: + const reader = readableStream.getReader({ mode: "byob" }); const { value: view, done } = await reader.read(new Uint8Array(1024), { min: 1024 }); @@ -1932,12 +1933,35 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by 1. If |buffer| is an abrupt completion, 1. Perform |readRequest|'s [=read request/error steps=], given |buffer|.\[[Value]]. 1. Return. - 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] - |buffer|.\[[Value]], [=pull-into descriptor/buffer byte length=] |autoAllocateChunkSize|, - [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte length=] - |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/minimum - fill=] 1, [=pull-into descriptor/element size=] 1, [=pull-into descriptor/view constructor=] - {{%Uint8Array%}}, and [=pull-into descriptor/reader type=] "`default`". + 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with + <dl class="props"> + <dt>[=pull-into descriptor/buffer=] + <dd>|buffer|.\[[Value]] + + <dt>[=pull-into descriptor/buffer byte length=] + <dd>|autoAllocateChunkSize| + + <dt>[=pull-into descriptor/byte offset=] + <dd>0 + + <dt>[=pull-into descriptor/byte length=] + <dd>|autoAllocateChunkSize| + + <dt>[=pull-into descriptor/bytes filled=] + <dd>0 + + <dt>[=pull-into descriptor/minimum fill=] + <dd>1 + + <dt>[=pull-into descriptor/element size=] + <dd>1 + + <dt>[=pull-into descriptor/view constructor=] + <dd>{{%Uint8Array%}} + + <dt>[=pull-into descriptor/reader type=] + <dd>"`default`" + </dl> 1. [=list/Append=] |pullIntoDescriptor| to [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=]. 1. Perform ! [$ReadableStreamAddReadRequest$](|stream|, |readRequest|). @@ -3580,7 +3604,7 @@ The following abstract operations support the implementation of the |view|.\[[TypedArrayName]]. 1. Set |ctor| to the constructor specified in [=the typed array constructors table=] for |view|.\[[TypedArrayName]]. - 1. Let |minimumFill| be |min| * |elementSize|. + 1. Let |minimumFill| be |min| &times; |elementSize|. 1. Assert: |minimumFill| ≥ 0 and |minimumFill| ≤ |view|.\[[ByteLength]]. 1. Assert: |minimumFill| mod |elementSize| is 0. 1. Let |byteOffset| be |view|.\[[ByteOffset]]. @@ -3590,12 +3614,35 @@ The following abstract operations support the implementation of the 1. Perform |readIntoRequest|'s [=read-into request/error steps=], given |bufferResult|.\[[Value]]. 1. Return. 1. Let |buffer| be |bufferResult|.\[[Value]]. - 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] - |buffer|, [=pull-into descriptor/buffer byte length=] |buffer|.\[[ArrayBufferByteLength]], - [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] - |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/minimum fill=] - |minimumFill|, [=pull-into descriptor/element size=] |elementSize|, [=pull-into descriptor/view - constructor=] |ctor|, and [=pull-into descriptor/reader type=] "`byob`". + 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with + <dl class="props"> + <dt>[=pull-into descriptor/buffer=] + <dd>|buffer| + + <dt>[=pull-into descriptor/buffer byte length=] + <dd>|buffer|.\[[ArrayBufferByteLength]] + + <dt>[=pull-into descriptor/byte offset=] + <dd>|byteOffset| + + <dt>[=pull-into descriptor/byte length=] + <dd>|byteLength| + + <dt>[=pull-into descriptor/bytes filled=] + <dd>0 + + <dt>[=pull-into descriptor/minimum fill=] + <dd>|minimumFill| + + <dt>[=pull-into descriptor/element size=] + <dd>|elementSize| + + <dt>[=pull-into descriptor/view constructor=] + <dd>|ctor| + + <dt>[=pull-into descriptor/reader type=] + <dd>"`byob`" + </dl> 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. [=list/Append=] |pullIntoDescriptor| to |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=]. From 99b7f4278f8f3d8d9b0b9c4221821d3a64a87688 Mon Sep 17 00:00:00 2001 From: Mattias Buelens <mattias@buelens.com> Date: Sat, 30 Sep 2023 11:06:26 +0200 Subject: [PATCH 40/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 979fc6bbb..b510d991a 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 979fc6bbbf20615228867c4bfe3b505cad17fe3a +Subproject commit b510d991a790775db5aeef6e48c70271edf01e7e From 547805f938e35160977caff29f0f2dee576bcfe7 Mon Sep 17 00:00:00 2001 From: Mattias Buelens <mattias@buelens.com> Date: Fri, 10 Nov 2023 19:27:50 +0100 Subject: [PATCH 41/42] Replace "x mod y" with "the remainder after dividing x by y" --- index.bs | 25 ++++++++++--------- .../lib/abstract-ops/readable-streams.js | 3 ++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 8d9547164..460afa8ec 100644 --- a/index.bs +++ b/index.bs @@ -3274,8 +3274,8 @@ The following abstract operations support the implementation of the 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. Let |firstPendingPullInto| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If |firstPendingPullInto|'s [=pull-into descriptor/bytes filled=] - mod |firstPendingPullInto|'s [=pull-into descriptor/element size=] is not 0, + 1. If the remainder after dividing |firstPendingPullInto|'s [=pull-into descriptor/bytes filled=] + by |firstPendingPullInto|'s [=pull-into descriptor/element size=] is not 0, 1. Let |e| be a new {{TypeError}} exception. 1. Perform ! [$ReadableByteStreamControllerError$](|controller|, |e|). 1. Throw |e|. @@ -3292,8 +3292,8 @@ The following abstract operations support the implementation of the 1. Assert: |pullIntoDescriptor|.[=pull-into descriptor/reader type=] is not "`none`". 1. Let |done| be false. 1. If |stream|.[=ReadableStream/[[state]]=] is "`closed`", - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] - mod |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. + 1. Assert: the remainder after dividing |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + by |pullIntoDescriptor|'s [=pull-into descriptor/element size=] is 0. 1. Set |done| to true. 1. Let |filledView| be ! [$ReadableByteStreamControllerConvertPullIntoDescriptor$](|pullIntoDescriptor|). @@ -3312,7 +3312,7 @@ The following abstract operations support the implementation of the 1. Let |bytesFilled| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. 1. Let |elementSize| be |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. 1. Assert: |bytesFilled| ≤ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. - 1. Assert: |bytesFilled| mod |elementSize| is 0. + 1. Assert: the remainder after dividing |bytesFilled| by |elementSize| is 0. 1. Let |buffer| be ! [$TransferArrayBuffer$](|pullIntoDescriptor|'s [=pull-into descriptor/buffer=]). 1. Return ! [$Construct$](|pullIntoDescriptor|'s [=pull-into descriptor/view constructor=], « |buffer|, |pullIntoDescriptor|'s [=pull-into descriptor/byte offset=], @@ -3451,8 +3451,9 @@ The following abstract operations support the implementation of the 1. Let |ready| be false. 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=]. - 1. Let |maxAlignedBytes| be |maxBytesFilled| − (|maxBytesFilled| mod |pullIntoDescriptor|'s - [=pull-into descriptor/element size=]). + 1. Let |remainderBytes| be the remainder after dividing |maxBytesFilled| by |pullIntoDescriptor|'s + [=pull-into descriptor/element size=]. + 1. Let |maxAlignedBytes| be |maxBytesFilled| − |remainderBytes|. 1. If |maxAlignedBytes| ≥ |pullIntoDescriptor|'s [=pull-into descriptor/minimum fill=], 1. Set |totalBytesToCopyRemaining| to |maxAlignedBytes| − |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. @@ -3618,7 +3619,7 @@ The following abstract operations support the implementation of the |view|.\[[TypedArrayName]]. 1. Let |minimumFill| be |min| &times; |elementSize|. 1. Assert: |minimumFill| ≥ 0 and |minimumFill| ≤ |view|.\[[ByteLength]]. - 1. Assert: |minimumFill| mod |elementSize| is 0. + 1. Assert: the remainder after dividing |minimumFill| by |elementSize| is 0. 1. Let |byteOffset| be |view|.\[[ByteOffset]]. 1. Let |byteLength| be |view|.\[[ByteLength]]. 1. Let |bufferResult| be [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). @@ -3710,8 +3711,8 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-closed-state">ReadableByteStreamControllerRespondInClosedState(|controller|, |firstDescriptor|)</dfn> performs the following steps: - 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] mod |firstDescriptor|'s - [=pull-into descriptor/element size=] is 0. + 1. Assert: the remainder after dividing |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + by |firstDescriptor|'s [=pull-into descriptor/element size=] is 0. 1. If |firstDescriptor|'s [=pull-into descriptor/reader type=] is "`none`", perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. @@ -3743,8 +3744,8 @@ The following abstract operations support the implementation of the that is not yet filled up to its minimum length will stay at the head of the queue, so the [=underlying source=] can keep filling it. 1. Perform ! [$ReadableByteStreamControllerShiftPendingPullInto$](|controller|). - 1. Let |remainderSize| be |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] mod - |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. + 1. Let |remainderSize| be the remainder after dividing |pullIntoDescriptor|'s + [=pull-into descriptor/bytes filled=] by |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. 1. If |remainderSize| > 0, 1. Let |end| be |pullIntoDescriptor|'s [=pull-into descriptor/byte offset=] + |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=]. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 9d20ff705..5cd4814b3 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1426,7 +1426,8 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, let totalBytesToCopyRemaining = maxBytesToCopy; let ready = false; assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.minimumFill); - const maxAlignedBytes = maxBytesFilled - maxBytesFilled % pullIntoDescriptor.elementSize; + const remainderBytes = maxBytesFilled % pullIntoDescriptor.elementSize; + const maxAlignedBytes = maxBytesFilled - remainderBytes; // A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head // of the queue, so the underlying source can keep filling it. if (maxAlignedBytes >= pullIntoDescriptor.minimumFill) { From b938532e0475af14808ba592eeccfd9d78c981ff Mon Sep 17 00:00:00 2001 From: Mattias Buelens <mattias@buelens.com> Date: Mon, 13 Nov 2023 11:54:54 +0100 Subject: [PATCH 42/42] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index b510d991a..7eaf605c3 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit b510d991a790775db5aeef6e48c70271edf01e7e +Subproject commit 7eaf605c38d80377c717828376deabad86b702b2