diff --git a/index.bs b/index.bs
index ac3e82e05..4e83d060e 100644
--- a/index.bs
+++ b/index.bs
@@ -1885,13 +1885,7 @@ ReadableByteStreamController(stream, underlyingByteSource,
1. If IsReadableByteStreamController(*this*) is *false*, throw a *TypeError* exception.
- 1. If *this*.[[byobRequest]] is *undefined* and *this*.[[pendingPullIntos]] is not empty,
- 1. Let _firstDescriptor_ be the first element of *this*.[[pendingPullIntos]].
- 1. Let _view_ be ! Construct(%Uint8Array%, « _firstDescriptor_.[[buffer]],
- _firstDescriptor_.[[byteOffset]] + _firstDescriptor_.[[bytesFilled]], _firstDescriptor_.[[byteLength]] −
- _firstDescriptor_.[[bytesFilled]] »).
- 1. Set *this*.[[byobRequest]] to ! Construct(`ReadableStreamBYOBRequest`, « *this*, _view_ »).
- 1. Return *this*.[[byobRequest]].
+ 1. Return ! ReadableByteStreamControllerGetBYOBRequest(*this*).
get desiredSize
@@ -2187,6 +2181,8 @@ nothrow>ReadableByteStreamControllerEnqueue ( controller, chunk<
1. Let _stream_ be _controller_.[[controlledReadableStream]].
1. Assert: _controller_.[[closeRequested]] is *false*.
1. Assert: _stream_.[[state]] is `"readable"`.
+ 1. Assert: Type(_chunk_) is Object.
+ 1. Assert: _chunk_ has a [[ViewedArrayBuffer]] internal slot.
1. Let _buffer_ be _chunk_.[[ViewedArrayBuffer]].
1. Let _byteOffset_ be _chunk_.[[ByteOffset]].
1. Let _byteLength_ be _chunk_.[[ByteLength]].
@@ -2285,6 +2281,20 @@ nothrow>ReadableByteStreamControllerFillPullIntoDescriptorFromQueue ( contr
1. Return _ready_.
+ReadableByteStreamControllerGetBYOBRequest ( controller )
+
+
+ 1. If _controller_.[[byobRequest]] is *undefined* and _controller_.[[pendingPullIntos]] is not empty,
+ 1. Let _firstDescriptor_ be the first element of _controller_.[[pendingPullIntos]].
+ 1. Let _view_ be ! Construct(%Uint8Array%, « _firstDescriptor_.[[buffer]],
+ _firstDescriptor_.[[byteOffset]] + _firstDescriptor_.[[bytesFilled]], _firstDescriptor_.[[byteLength]] −
+ _firstDescriptor_.[[bytesFilled]] »).
+ 1. Set _controller_.[[byobRequest]] to ! Construct(`ReadableStreamBYOBRequest`,
+ « _controller_, _view_ »).
+ 1. Return _controller_.[[byobRequest]].
+
+
ReadableByteStreamControllerGetDesiredSize ( controller )
diff --git a/reference-implementation/lib/readable-stream.js b/reference-implementation/lib/readable-stream.js
index 4852188fe..164f783a3 100644
--- a/reference-implementation/lib/readable-stream.js
+++ b/reference-implementation/lib/readable-stream.js
@@ -256,6 +256,11 @@ class ReadableStream {
module.exports = {
ReadableStream,
IsReadableStreamDisturbed,
+ ReadableByteStreamControllerClose,
+ ReadableByteStreamControllerEnqueue,
+ ReadableByteStreamControllerError,
+ ReadableByteStreamControllerGetBYOBRequest,
+ ReadableByteStreamControllerGetDesiredSize,
ReadableStreamDefaultControllerClose,
ReadableStreamDefaultControllerEnqueue,
ReadableStreamDefaultControllerError,
@@ -1212,16 +1217,7 @@ class ReadableByteStreamController {
throw byteStreamControllerBrandCheckException('byobRequest');
}
- if (this._byobRequest === undefined && this._pendingPullIntos.length > 0) {
- const firstDescriptor = this._pendingPullIntos[0];
- const view = new Uint8Array(firstDescriptor.buffer,
- firstDescriptor.byteOffset + firstDescriptor.bytesFilled,
- firstDescriptor.byteLength - firstDescriptor.bytesFilled);
-
- this._byobRequest = new ReadableStreamBYOBRequest(this, view);
- }
-
- return this._byobRequest;
+ return ReadableByteStreamControllerGetBYOBRequest(this);
}
get desiredSize() {
@@ -1735,6 +1731,7 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) {
assert(controller._closeRequested === false);
assert(stream._state === 'readable');
+ assert(ArrayBuffer.isView(chunk) === true);
const buffer = chunk.buffer;
const byteOffset = chunk.byteOffset;
@@ -1772,6 +1769,19 @@ function ReadableByteStreamControllerError(controller, e) {
ReadableStreamError(stream, e);
}
+function ReadableByteStreamControllerGetBYOBRequest(controller) {
+ if (controller._byobRequest === undefined && controller._pendingPullIntos.length > 0) {
+ const firstDescriptor = controller._pendingPullIntos[0];
+ const view = new Uint8Array(firstDescriptor.buffer,
+ firstDescriptor.byteOffset + firstDescriptor.bytesFilled,
+ firstDescriptor.byteLength - firstDescriptor.bytesFilled);
+
+ controller._byobRequest = new ReadableStreamBYOBRequest(controller, view);
+ }
+
+ return controller._byobRequest;
+}
+
function ReadableByteStreamControllerGetDesiredSize(controller) {
return controller._strategyHWM - controller._totalQueuedBytes;
}
diff --git a/reference-implementation/lib/transform-stream.js b/reference-implementation/lib/transform-stream.js
index cf0ab5154..370292161 100644
--- a/reference-implementation/lib/transform-stream.js
+++ b/reference-implementation/lib/transform-stream.js
@@ -3,7 +3,10 @@ const assert = require('assert');
const { InvokeOrNoop, PromiseInvokeOrPerformFallback, PromiseInvokeOrNoop, typeIsObject } = require('./helpers.js');
const { ReadableStream, ReadableStreamDefaultControllerClose,
ReadableStreamDefaultControllerEnqueue, ReadableStreamDefaultControllerError,
- ReadableStreamDefaultControllerGetDesiredSize } = require('./readable-stream.js');
+ ReadableStreamDefaultControllerGetDesiredSize,
+ ReadableByteStreamControllerClose, ReadableByteStreamControllerEnqueue,
+ ReadableByteStreamControllerError, ReadableByteStreamControllerGetBYOBRequest,
+ ReadableByteStreamControllerGetDesiredSize } = require('./readable-stream.js');
const { WritableStream, WritableStreamDefaultControllerError } = require('./writable-stream.js');
// Methods on the transform stream controller object
@@ -37,19 +40,28 @@ function TransformStreamEnqueueToReadable(transformStream, chunk) {
// accept TransformStreamEnqueueToReadable() calls.
const controller = transformStream._readableController;
+ const type = transformStream._readableType;
+ assert(type === undefined || type === 'bytes');
- try {
- ReadableStreamDefaultControllerEnqueue(controller, chunk);
- } catch (e) {
- // This happens when readableStrategy.size() throws.
- // The ReadableStream has already errored itself.
- transformStream._readableClosed = true;
- TransformStreamErrorIfNeeded(transformStream, e);
-
- throw transformStream._storedError;
+ if (type === 'bytes') {
+ if (ArrayBuffer.isView(chunk) === false) {
+ throw new TypeError('You can only enqueue array buffer views when readableType is "bytes"');
+ }
+ ReadableByteStreamControllerEnqueue(controller, chunk);
+ } else if (type === undefined) {
+ try {
+ ReadableStreamDefaultControllerEnqueue(controller, chunk);
+ } catch (e) {
+ // This happens when readableStrategy.size() throws.
+ // The ReadableStream has already errored itself.
+ transformStream._readableClosed = true;
+ TransformStreamErrorIfNeeded(transformStream, e);
+
+ throw transformStream._storedError;
+ }
}
- const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);
+ const desiredSize = TransformStreamGetDesiredSize(transformStream);
const maybeBackpressure = desiredSize <= 0;
if (maybeBackpressure === true && transformStream._backpressure === false) {
@@ -76,10 +88,14 @@ function TransformStreamCloseReadableInternal(transformStream) {
assert(transformStream._errored === false);
assert(transformStream._readableClosed === false);
- try {
- ReadableStreamDefaultControllerClose(transformStream._readableController);
- } catch (e) {
- assert(false);
+ const readableController = transformStream._readableController;
+ const type = transformStream._readableType;
+ assert(type === undefined || type === 'bytes');
+
+ if (type === 'bytes') {
+ ReadableByteStreamControllerClose(readableController);
+ } else if (type === undefined) {
+ ReadableStreamDefaultControllerClose(readableController);
}
transformStream._readableClosed = true;
@@ -99,11 +115,23 @@ function TransformStreamErrorInternal(transformStream, e) {
transformStream._errored = true;
transformStream._storedError = e;
+ const writableController = transformStream._writableController;
+ const readableController = transformStream._readableController;
+
+ const writableType = transformStream._writableType;
+ const readableType = transformStream._readableType;
+ assert(writableType === undefined);
+ assert(readableType === 'bytes' || readableType === undefined);
+
if (transformStream._writableDone === false) {
- WritableStreamDefaultControllerError(transformStream._writableController, e);
+ WritableStreamDefaultControllerError(writableController, e);
}
if (transformStream._readableClosed === false) {
- ReadableStreamDefaultControllerError(transformStream._readableController, e);
+ if (readableType === 'bytes') {
+ ReadableByteStreamControllerError(readableController, e);
+ } else if (readableType === undefined) {
+ ReadableStreamDefaultControllerError(readableController, e);
+ }
}
}
@@ -176,6 +204,19 @@ function TransformStreamTransform(transformStream, chunk) {
e => TransformStreamErrorIfNeeded(transformStream, e));
}
+function TransformStreamGetDesiredSize(transformStream) {
+ const type = transformStream._readableType;
+ const controller = transformStream._readableController;
+
+ assert(type === undefined || type === 'bytes');
+
+ if (type === 'bytes') {
+ return ReadableByteStreamControllerGetDesiredSize(controller);
+ } else if (type === undefined) {
+ return ReadableStreamDefaultControllerGetDesiredSize(controller);
+ }
+}
+
function IsTransformStreamDefaultController(x) {
if (!typeIsObject(x)) {
return false;
@@ -201,9 +242,13 @@ function IsTransformStream(x) {
}
class TransformStreamSink {
- constructor(transformStream, startPromise) {
+ constructor(transformStream, startPromise, type) {
+ if (type !== undefined) {
+ throw TypeError(`writableType cannot be ${type}`);
+ }
this._transformStream = transformStream;
this._startPromise = startPromise;
+ this.type = type;
}
start(c) {
@@ -256,9 +301,13 @@ class TransformStreamSink {
}
class TransformStreamSource {
- constructor(transformStream, startPromise) {
+ constructor(transformStream, startPromise, type) {
+ if (type !== undefined && type !== 'bytes') {
+ throw TypeError(`readableType cannot be ${type}`);
+ }
this._transformStream = transformStream;
this._startPromise = startPromise;
+ this.type = type;
}
start(c) {
@@ -321,15 +370,28 @@ class TransformStreamDefaultController {
this._controlledTransformStream = transformStream;
}
+ get byobRequest() {
+ if (IsTransformStreamDefaultController(this) === false) {
+ throw defaultControllerBrandCheckException('byobRequest');
+ }
+
+ if (this._readableType !== 'bytes') {
+ return undefined;
+ }
+
+ const readableController = this._readableController;
+
+ return ReadableByteStreamControllerGetBYOBRequest(readableController);
+ }
+
get desiredSize() {
if (IsTransformStreamDefaultController(this) === false) {
throw defaultControllerBrandCheckException('desiredSize');
}
const transformStream = this._controlledTransformStream;
- const readableController = transformStream._readableController;
- return ReadableStreamDefaultControllerGetDesiredSize(readableController);
+ return TransformStreamGetDesiredSize(transformStream);
}
enqueue(chunk) {
@@ -379,23 +441,26 @@ class TransformStream {
this._transformStreamController = new TransformStreamDefaultController(this);
+ this._readableType = transformer.readableType;
+ this._writableType = transformer.writableType;
+
let startPromise_resolve;
const startPromise = new Promise(resolve => {
startPromise_resolve = resolve;
});
- const source = new TransformStreamSource(this, startPromise);
+ const source = new TransformStreamSource(this, startPromise, this._readableType);
this._readable = new ReadableStream(source, readableStrategy);
- const sink = new TransformStreamSink(this, startPromise);
+ const sink = new TransformStreamSink(this, startPromise, this._writableType);
this._writable = new WritableStream(sink, writableStrategy);
assert(this._writableController !== undefined);
assert(this._readableController !== undefined);
- const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(this._readableController);
+ const desiredSize = TransformStreamGetDesiredSize(this);
// Set _backpressure based on desiredSize. As there is no read() at this point, we can just interpret
// desiredSize being non-positive as backpressure.
TransformStreamSetBackpressure(this, desiredSize <= 0);