diff --git a/index.bs b/index.bs index e7351289a..ef32673f0 100644 --- a/index.bs +++ b/index.bs @@ -422,10 +422,10 @@ Instances of {{ReadableStream}} are created with the internal slots described in state via the passed controller object. This is an example of the revealing constructor pattern. - If the underlyingSource object contains a truthy property byob, this readable stream is - a readable byte stream, and can successfully vend BYOB readers. In that case, the passed - controller object will be an instance of {{ReadableByteStreamController}}. Otherwise, it will be an instance of - {{ReadableStreamDefaultController}}. + If the underlyingSource object contains a property type set to "bytes", this + readable stream is a readable byte stream, and can successfully vend BYOB readers. In that case, + the passed controller object will be an instance of {{ReadableByteStreamController}}. Otherwise, it will + be an instance of {{ReadableStreamDefaultController}}. For readable byte streams, underlyingSource can also contain a property autoAllocateChunkSize, which can be set to a positive integer to enable the auto-allocation feature for @@ -447,16 +447,16 @@ Instances of {{ReadableStream}} are created with the internal slots described in 1. Set *this*@[[reader]] and *this*@[[storedError]] to *undefined*. 1. Set *this*@[[disturbed]] to *false*. 1. Set *this*@[[readableStreamController]] to *undefined*. - 1. Let _byob_ be ToBoolean(GetV(_underlyingSource_, `"byob"`)). - 1. ReturnIfAbrupt(_byob_). - 1. If _byob_ is *true*, - 1. If _highWaterMark_ is *undefined*, - 1. Let _highWaterMark_ be 0. + 1. Let _type_ be GetV(_underlyingSource_, `"type"`). + 1. ReturnIfAbrupt(_type_). + 1. Let _typeString_ be ToString(_type_). + 1. If _typeString_ is `"bytes"`, + 1. If _highWaterMark_ is *undefined*, let _highWaterMark_ be 0. 1. Set *this*@[[readableStreamController]] to Construct(`ReadableByteStreamController`, «*this*, _underlyingSource_, _highWaterMark_»). - 1. Otherwise, - 1. If _highWaterMark_ is *undefined*, - 1. Let _highWaterMark_ be 1. + 1. Otherwise, if _type_ is *undefined*, + 1. If _highWaterMark_ is *undefined*, let _highWaterMark_ be 1. 1. Set *this*@[[readableStreamController]] to Construct(`ReadableStreamDefaultController`, «*this*, _underlyingSource_, _size_, _highWaterMark_»). + 1. Otherwise, throw a *RangeError* exception.

Properties of the {{ReadableStream}} Prototype

@@ -3149,7 +3149,7 @@ BYOB reader, to move the data from the stream's internal queue to the developer- const socket = createHypotheticalSelect2Socket(host, port); return new ReadableStream({ - byob: true, + type: "bytes", start(controller) { socket.setTCPWindowSize(Math.max(0, controller.desiredSize)); @@ -3256,7 +3256,7 @@ size of 1024, it attempts to fill the developer-supplied buffer, allowing full c let position = 0; return new ReadableStream({ - byob: true, + type: "bytes", start() { return fs.open(filename, "r").then(result => { diff --git a/reference-implementation/lib/readable-stream.js b/reference-implementation/lib/readable-stream.js index 2b0c75ea4..9a2555fae 100644 --- a/reference-implementation/lib/readable-stream.js +++ b/reference-implementation/lib/readable-stream.js @@ -22,17 +22,20 @@ export default class ReadableStream { // Initialize to undefined first because the constructor of the controller checks this // variable to validate the caller. this._readableStreamController = undefined; - const byob = underlyingSource['byob']; - if (byob === true) { + const type = underlyingSource.type; + const typeString = String(type); + if (typeString === 'bytes') { if (highWaterMark === undefined) { highWaterMark = 0; } this._readableStreamController = new ReadableByteStreamController(this, underlyingSource, highWaterMark); - } else { + } else if (type === undefined) { if (highWaterMark === undefined) { highWaterMark = 1; } this._readableStreamController = new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark); + } else { + throw new RangeError('Invalid type is specified'); } } diff --git a/reference-implementation/test/readable-byte-stream.js b/reference-implementation/test/readable-byte-stream.js index 16d0f44f6..1dd28b65b 100644 --- a/reference-implementation/test/readable-byte-stream.js +++ b/reference-implementation/test/readable-byte-stream.js @@ -2,7 +2,7 @@ const test = require('tape-catch'); test('ReadableStream with byte source can be constructed with no errors', t => { t.doesNotThrow( - () => new ReadableStream({ byob: true }), + () => new ReadableStream({ type: 'bytes' }), 'ReadableStream with byte source constructed with an empty underlying byte source object as parameter'); t.end(); }); @@ -21,7 +21,7 @@ test('ReadableStream with byte source: Construct and expect start and pull being t.equals(controller.desiredSize, 256, 'desiredSize'); t.end(); }, - byob: true + type: 'bytes' }, { highWaterMark: 256 }); @@ -46,7 +46,7 @@ test('ReadableStream with byte source: No automatic pull call if start doesn\'t ++pullCount; }, - byob: true + type: 'bytes' }, { highWaterMark: 256 }); @@ -64,7 +64,7 @@ test('ReadableStream with byte source: Construct with highWaterMark of 0', t => t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }, { highWaterMark: 0 }); @@ -76,7 +76,7 @@ test('ReadableStream with byte source: Construct with highWaterMark of 0', t => test('ReadableStream with byte source: getReader(), then releaseLock()', t => { const stream = new ReadableStream({ - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -92,7 +92,7 @@ test('ReadableStream with byte source: getReader(), then releaseLock()', t => { test('ReadableStream with byte source: getReader() with mode set to byob, then releaseLock()', t => { const stream = new ReadableStream({ - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -115,7 +115,7 @@ test('ReadableStream with byte source: Test that closing a stream does not relea t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -146,7 +146,7 @@ test('ReadableStream with byte source: Test that closing a stream does not relea t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -179,7 +179,7 @@ test('ReadableStream with byte source: Test that erroring a stream does not rele t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -215,7 +215,7 @@ test('ReadableStream with byte source: Test that erroring a stream does not rele t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -241,7 +241,7 @@ test('ReadableStream with byte source: Test that erroring a stream does not rele test('ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw', t => { const stream = new ReadableStream({ - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -267,7 +267,7 @@ test('ReadableStream with byte source: Automatic pull() after start()', t => { pull() { ++pullCount; }, - byob: true + type: 'bytes' }, { highWaterMark: 8 }); @@ -290,7 +290,7 @@ test('ReadableStream with byte source: Automatic pull() after start() and read() pull() { ++pullCount; }, - byob: true + type: 'bytes' }, { highWaterMark: 0 }); @@ -336,7 +336,7 @@ test('ReadableStream with byte source: autoAllocateChunkSize', t => { ++pullCount; }, - byob: true, + type: 'bytes', autoAllocateChunkSize: 16 }, { highWaterMark: 0 @@ -408,7 +408,7 @@ test('ReadableStream with byte source: Mix of auto allocate and BYOB', t => { ++pullCount; }, - byob: true, + type: 'bytes', autoAllocateChunkSize: 16 }, { highWaterMark: 0 @@ -449,7 +449,7 @@ test('ReadableStream with byte source: Automatic pull() after start() and read(v pull() { ++pullCount; }, - byob: true + type: 'bytes' }, { highWaterMark: 0 }); @@ -485,7 +485,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then read()', t = t.equals(controller.desiredSize, 8, 'desiredSize in pull()'); } }, - byob: true + type: 'bytes' }, { highWaterMark: 8 }); @@ -518,7 +518,7 @@ test('ReadableStream with byte source: Push source that doesn\'t understand pull start(c) { controller = c; }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -541,7 +541,7 @@ test('ReadableStream with byte source: Push source that doesn\'t understand pull test('ReadableStream with byte source: read(), but pull() function is not callable', t => { const stream = new ReadableStream({ pull: 'foo', - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -558,7 +558,7 @@ test('ReadableStream with byte source: read(), but pull() function is not callab test('ReadableStream with byte source: read(view), but pull() function is not callable', t => { const stream = new ReadableStream({ pull: 'foo', - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -577,7 +577,7 @@ test('ReadableStream with byte source: enqueue() with Uint16Array, getReader(), start(c) { c.enqueue(new Uint16Array(16)); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -607,7 +607,7 @@ test('ReadableStream with byte source: enqueue(), read(view) partially, then rea t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const byobReader = stream.getReader({mode: 'byob'}); @@ -655,7 +655,7 @@ test('ReadableStream with byte source: getReader(), enqueue(), close(), then rea t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -692,7 +692,7 @@ test('ReadableStream with byte source: enqueue(), close(), getReader(), then rea t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -727,7 +727,7 @@ test('ReadableStream with byte source: Respond to pull() by enqueue()', t => { controller.enqueue(new Uint8Array(16)); t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -771,7 +771,7 @@ test('ReadableStream with byte source: Respond to pull() by enqueue() asynchrono ++pullCount; }, - byob: true + type: 'bytes' }, { highWaterMark: 256 }); @@ -829,7 +829,7 @@ test('ReadableStream with byte source: read(view), then respond()', t => { ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -875,7 +875,7 @@ test('ReadableStream with byte source: read(view), then respond() with a transfe ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -919,7 +919,7 @@ test('ReadableStream with byte source: read(view), then respond() with too big v ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -964,7 +964,7 @@ test('ReadableStream with byte source: respond(3) to read(view) with 2 element U controller.byobRequest.respond(3); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1013,7 +1013,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then read(view)', pull() { t.equals(controller.byobRequest, undefined, 'byobRequest is undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1057,7 +1057,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then cancel()', t ++cancelCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -1097,7 +1097,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then cancel()', t ++cancelCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1143,7 +1143,7 @@ test('ReadableStream with byte source: getReader(), read(view), then cancel()', return 'bar'; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1188,7 +1188,7 @@ test('ReadableStream with byte source: cancel() with partially filled pending pu ++pullCount; }, - byob: true + type: 'bytes' }); Promise.resolve().then(() => { @@ -1229,7 +1229,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then read(view) w pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1273,7 +1273,7 @@ test('ReadableStream with byte source: Multiple enqueue(), getReader(), then rea pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1304,7 +1304,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then read(view) w pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1335,7 +1335,7 @@ test('ReadableStream with byte source: enqueue(), getReader(), then read(view) w pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1391,7 +1391,7 @@ test('ReadableStream with byte source: enqueue() 1 byte, getReader(), then read( view[0] = 0xaa; controller.byobRequest.respond(1); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1449,7 +1449,7 @@ test('ReadableStream with byte source: enqueue() 3 byte, getReader(), then read( ++pullCount; }, - byob: true + type: 'bytes' }); // Wait for completion of the start method to be reflected. @@ -1503,7 +1503,7 @@ test('ReadableStream with byte source: read(view) with Uint16Array on close()-d t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1553,7 +1553,7 @@ test('ReadableStream with byte source: A stream must be errored if close()-d bef ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1591,7 +1591,7 @@ test('ReadableStream with byte source: Throw if close()-ed more than once', t => start(c) { controller = c; }, - byob: true + type: 'bytes' }); // Enqueue a chunk so that the stream doesn't get closed. This is to check duplicate close() calls are rejected @@ -1619,7 +1619,7 @@ test('ReadableStream with byte source: Throw on enqueue() after close()', t => { start(c) { controller = c; }, - byob: true + type: 'bytes' }); // Enqueue a chunk so that the stream doesn't get closed. This is to check enqueue() after close() is rejected @@ -1661,7 +1661,7 @@ test('ReadableStream with byte source: read(view), then respond() and close() in controller.byobRequest.respond(16); controller.close(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1723,7 +1723,7 @@ test('ReadableStream with byte source: read(view) with Uint32Array, then fill it ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1762,7 +1762,7 @@ test('ReadableStream with byte source: read() twice, then enqueue() twice', t => ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -1839,7 +1839,7 @@ test('ReadableStream with byte source: Multiple read(view), close() and respond( ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1899,7 +1899,7 @@ test('ReadableStream with byte source: Multiple read(view), big enqueue()', t => ++pullCount; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1943,7 +1943,7 @@ test('ReadableStream with byte source: Multiple read(view) and multiple enqueue( t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1979,7 +1979,7 @@ test('ReadableStream with byte source: read(view) with passing undefined as view pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -1998,7 +1998,7 @@ test('ReadableStream with byte source: read(view) with zero-length view must fai pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2017,7 +2017,7 @@ test('ReadableStream with byte source: read(view) with passing an empty object a pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2037,7 +2037,7 @@ test('ReadableStream with byte source: Even read(view) with passing ArrayBufferV pull() { t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2062,7 +2062,7 @@ test('ReadableStream with byte source: read() on an errored stream', t => { t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -2085,7 +2085,7 @@ test('ReadableStream with byte source: read(), then error()', t => { start(c) { controller = c; }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -2112,7 +2112,7 @@ test('ReadableStream with byte source: read(view) on an errored stream', t => { t.fail('pull must not be called'); t.end(); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2135,7 +2135,7 @@ test('ReadableStream with byte source: read(view), then error()', t => { start(c) { controller = c; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2164,7 +2164,7 @@ test('ReadableStream with byte source: Throwing in pull function must error the t.equals(controller.byobRequest, undefined, 'byobRequest must be undefined'); throw testError; }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -2196,7 +2196,7 @@ test('ReadableStream with byte source: Throwing in pull in response to read() mu controller.error(passedError); throw new TypeError('foo'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader(); @@ -2227,7 +2227,7 @@ test('ReadableStream with byte source: Throwing in pull in response to read(view t.notEqual(controller.byobRequest, undefined, 'byobRequest must not be undefined'); throw testError; }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); @@ -2259,7 +2259,7 @@ test('ReadableStream with byte source: Throwing in pull in response to read(view controller.error(passedError); throw new TypeError('foo'); }, - byob: true + type: 'bytes' }); const reader = stream.getReader({mode: 'byob'}); diff --git a/reference-implementation/web-platform-tests/readable-streams/general.js b/reference-implementation/web-platform-tests/readable-streams/general.js index b0e44f80d..30eb7ab81 100644 --- a/reference-implementation/web-platform-tests/readable-streams/general.js +++ b/reference-implementation/web-platform-tests/readable-streams/general.js @@ -10,6 +10,7 @@ test(() => { new ReadableStream(); // ReadableStream constructed with no parameters new ReadableStream({ }); // ReadableStream constructed with an empty object as parameter + new ReadableStream({ type: undefined }); // ReadableStream constructed with undefined type new ReadableStream(undefined); // ReadableStream constructed with undefined as parameter let x; @@ -23,6 +24,17 @@ test(() => { }, 'ReadableStream can\'t be constructed with garbage'); +test(() => { + + assert_throws(new RangeError(), () => new ReadableStream({ type: null }), + 'constructor should throw when the type is null'); + assert_throws(new RangeError(), () => new ReadableStream({ type: '' }), + 'constructor should throw when the type is empty string'); + assert_throws(new RangeError(), () => new ReadableStream({ type: 'asdf' }), + 'constructor should throw when the type is asdf'); + +}, 'ReadableStream can\'t be constructed with an invalid type'); + test(() => { const methods = ['cancel', 'constructor', 'getReader', 'pipeThrough', 'pipeTo', 'tee'];