OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Implementation of WritableStream for Blink. See | 5 // Implementation of WritableStream for Blink. See |
6 // https://streams.spec.whatwg.org/#ws. The implementation closely follows the | 6 // https://streams.spec.whatwg.org/#ws. The implementation closely follows the |
7 // standard, except where required for performance or integration with Blink. In | 7 // standard, except where required for performance or integration with Blink. In |
8 // particular, classes, methods and abstract operations are implemented in the | 8 // particular, classes, methods and abstract operations are implemented in the |
9 // same order as in the standard, to simplify side-by-side reading. | 9 // same order as in the standard, to simplify side-by-side reading. |
10 | 10 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 const Number = global.Number; | 63 const Number = global.Number; |
64 const Number_isNaN = Number.isNaN; | 64 const Number_isNaN = Number.isNaN; |
65 const Number_isFinite = Number.isFinite; | 65 const Number_isFinite = Number.isFinite; |
66 | 66 |
67 const Promise = global.Promise; | 67 const Promise = global.Promise; |
68 const thenPromise = v8.uncurryThis(Promise.prototype.then); | 68 const thenPromise = v8.uncurryThis(Promise.prototype.then); |
69 const Promise_resolve = v8.simpleBind(Promise.resolve, Promise); | 69 const Promise_resolve = v8.simpleBind(Promise.resolve, Promise); |
70 const Promise_reject = v8.simpleBind(Promise.reject, Promise); | 70 const Promise_reject = v8.simpleBind(Promise.reject, Promise); |
71 | 71 |
72 // User-visible strings. | 72 // User-visible strings. |
73 // TODO(ricea): Share strings with ReadableStream that are identical in both. | 73 const streamErrors = binding.streamErrors; |
74 const errIllegalInvocation = 'Illegal invocation'; | 74 const errAbortLockedStream = 'Cannot abort a writable stream that is locked to
a writer'; |
75 const errIllegalConstructor = 'Illegal constructor'; | |
76 const errInvalidType = 'Invalid type is specified'; | |
77 const errAbortLockedStream = 'Cannot abort a writable stream that is locked t
o a writer'; | |
78 const errStreamAborted = 'The stream has been aborted'; | 75 const errStreamAborted = 'The stream has been aborted'; |
79 const errWriterLockReleasedPrefix = 'This writable stream writer has been rele
ased and cannot be '; | 76 const errWriterLockReleasedPrefix = 'This writable stream writer has been rele
ased and cannot be '; |
80 const errCloseCloseRequestedStream = | 77 const errCloseCloseRequestedStream = |
81 'Cannot close a writable stream that has already been requested to be clos
ed'; | 78 'Cannot close a writable stream that has already been requested to be clos
ed'; |
82 const errWriteCloseRequestedStream = | 79 const errWriteCloseRequestedStream = |
83 'Cannot write to a writable stream that is due to be closed'; | 80 'Cannot write to a writable stream that is due to be closed'; |
84 const templateErrorCannotActionOnStateStream = | 81 const templateErrorCannotActionOnStateStream = |
85 (action, state) => `Cannot ${action} a ${state} writable stream`; | 82 (action, state) => `Cannot ${action} a ${state} writable stream`; |
86 const errReleasedWriterClosedPromise = | 83 const errReleasedWriterClosedPromise = |
87 'This writable stream writer has been released and cannot be used to monit
or the stream\'s state'; | 84 'This writable stream writer has been released and cannot be used to monit
or the stream\'s state'; |
88 const templateErrorIsNotAFunction = f => `${f} is not a function`; | 85 const templateErrorIsNotAFunction = f => `${f} is not a function`; |
89 const errSizeNotAFunction = | |
90 'A queuing strategy\'s size property must be a function'; | |
91 const errInvalidHWM = | |
92 'A queuing strategy\'s highWaterMark property must be a non-negative, non-
NaN number'; | |
93 const errInvalidSize = | |
94 'The return value of a queuing strategy\'s size function must be a finite,
non-NaN, non-negative number'; | |
95 | 86 |
96 // These verbs are used after errWriterLockReleasedPrefix | 87 // These verbs are used after errWriterLockReleasedPrefix |
97 const verbUsedToGetTheDesiredSize = 'used to get the desiredSize'; | 88 const verbUsedToGetTheDesiredSize = 'used to get the desiredSize'; |
98 const verbAborted = 'aborted'; | 89 const verbAborted = 'aborted'; |
99 const verbClosed = 'closed'; | 90 const verbClosed = 'closed'; |
100 const verbWrittenTo = 'written to'; | 91 const verbWrittenTo = 'written to'; |
101 | 92 |
102 // Utility functions (not from the standard). | 93 // Utility functions (not from the standard). |
103 function createWriterLockReleasedError(verb) { | 94 function createWriterLockReleasedError(verb) { |
104 return new TypeError(errWriterLockReleasedPrefix + verb); | 95 return new TypeError(errWriterLockReleasedPrefix + verb); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 | 156 |
166 class WritableStream { | 157 class WritableStream { |
167 constructor(underlyingSink = {}, { size, highWaterMark = 1 } = {}) { | 158 constructor(underlyingSink = {}, { size, highWaterMark = 1 } = {}) { |
168 this[_state] = WRITABLE; | 159 this[_state] = WRITABLE; |
169 this[_storedError] = undefined; | 160 this[_storedError] = undefined; |
170 this[_writer] = undefined; | 161 this[_writer] = undefined; |
171 this[_writableStreamController] = undefined; | 162 this[_writableStreamController] = undefined; |
172 this[_writeRequests] = new v8.InternalPackedArray(); | 163 this[_writeRequests] = new v8.InternalPackedArray(); |
173 const type = underlyingSink.type; | 164 const type = underlyingSink.type; |
174 if (type !== undefined) { | 165 if (type !== undefined) { |
175 throw new RangeError(errInvalidType); | 166 throw new RangeError(streamErrors.invalidType); |
176 } | 167 } |
177 this[_writableStreamController] = | 168 this[_writableStreamController] = |
178 new WritableStreamDefaultController(this, underlyingSink, size, | 169 new WritableStreamDefaultController(this, underlyingSink, size, |
179 highWaterMark); | 170 highWaterMark); |
180 } | 171 } |
181 | 172 |
182 get locked() { | 173 get locked() { |
183 if (!IsWritableStream(this)) { | 174 if (!IsWritableStream(this)) { |
184 throw new TypeError(errIllegalInvocation); | 175 throw new TypeError(streamErrors.illegalInvocation); |
185 } | 176 } |
186 return IsWritableStreamLocked(this); | 177 return IsWritableStreamLocked(this); |
187 } | 178 } |
188 | 179 |
189 abort(reason) { | 180 abort(reason) { |
190 if (!IsWritableStream(this)) { | 181 if (!IsWritableStream(this)) { |
191 return Promise_reject(new TypeError(errIllegalInvocation)); | 182 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
192 } | 183 } |
193 if (IsWritableStreamLocked(this)) { | 184 if (IsWritableStreamLocked(this)) { |
194 return Promise_reject(new TypeError(errAbortLockedStream)); | 185 return Promise_reject(new TypeError(errAbortLockedStream)); |
195 } | 186 } |
196 return WritableStreamAbort(this, reason); | 187 return WritableStreamAbort(this, reason); |
197 } | 188 } |
198 | 189 |
199 getWriter() { | 190 getWriter() { |
200 if (!IsWritableStream(this)) { | 191 if (!IsWritableStream(this)) { |
201 throw new TypeError(errIllegalInvocation); | 192 throw new TypeError(streamErrors.illegalInvocation); |
202 } | 193 } |
203 return AcquireWritableStreamDefaultWriter(this); | 194 return AcquireWritableStreamDefaultWriter(this); |
204 } | 195 } |
205 } | 196 } |
206 | 197 |
207 // General Writable Stream Abstract Operations | 198 // General Writable Stream Abstract Operations |
208 | 199 |
209 function AcquireWritableStreamDefaultWriter(stream) { | 200 function AcquireWritableStreamDefaultWriter(stream) { |
210 return new WritableStreamDefaultWriter(stream); | 201 return new WritableStreamDefaultWriter(stream); |
211 } | 202 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 } else { | 288 } else { |
298 TEMP_ASSERT(backpressure === false, | 289 TEMP_ASSERT(backpressure === false, |
299 'backpressure is false.'); | 290 'backpressure is false.'); |
300 v8.resolvePromise(writer[_readyPromise], undefined); | 291 v8.resolvePromise(writer[_readyPromise], undefined); |
301 } | 292 } |
302 } | 293 } |
303 | 294 |
304 class WritableStreamDefaultWriter { | 295 class WritableStreamDefaultWriter { |
305 constructor(stream) { | 296 constructor(stream) { |
306 if (!IsWritableStream(stream)) { | 297 if (!IsWritableStream(stream)) { |
307 throw new TypeError(errIllegalConstructor); | 298 throw new TypeError(streamErrors.illegalConstructor); |
308 } | 299 } |
309 if (IsWritableStreamLocked(stream)) { | 300 if (IsWritableStreamLocked(stream)) { |
310 throw new TypeError(errIllegalConstructor); | 301 throw new TypeError(streamErrors.illegalConstructor); |
311 } | 302 } |
312 this[_ownerWritableStream] = stream; | 303 this[_ownerWritableStream] = stream; |
313 stream[_writer] = this; | 304 stream[_writer] = this; |
314 const state = stream[_state]; | 305 const state = stream[_state]; |
315 if (state === WRITABLE || state === CLOSING) { | 306 if (state === WRITABLE || state === CLOSING) { |
316 this[_closedPromise] = v8.createPromise(); | 307 this[_closedPromise] = v8.createPromise(); |
317 } else if (state === CLOSED) { | 308 } else if (state === CLOSED) { |
318 this[_closedPromise] = Promise_resolve(undefined); | 309 this[_closedPromise] = Promise_resolve(undefined); |
319 } else { | 310 } else { |
320 TEMP_ASSERT(state === ERRORED, | 311 TEMP_ASSERT(state === ERRORED, |
321 'state is "errored".'); | 312 'state is "errored".'); |
322 this[_closedPromise] = Promise_reject(stream[_storedError]); | 313 this[_closedPromise] = Promise_reject(stream[_storedError]); |
323 } | 314 } |
324 if (state === WRITABLE && | 315 if (state === WRITABLE && |
325 WritableStreamDefaultControllerGetBackpressure( | 316 WritableStreamDefaultControllerGetBackpressure( |
326 stream[_writableStreamController])) { | 317 stream[_writableStreamController])) { |
327 this[_readyPromise] = v8.createPromise(); | 318 this[_readyPromise] = v8.createPromise(); |
328 } else { | 319 } else { |
329 this[_readyPromise] = Promise_resolve(undefined); | 320 this[_readyPromise] = Promise_resolve(undefined); |
330 } | 321 } |
331 } | 322 } |
332 | 323 |
333 get closed() { | 324 get closed() { |
334 if (!IsWritableStreamDefaultWriter(this)) { | 325 if (!IsWritableStreamDefaultWriter(this)) { |
335 return Promise_reject(new TypeError(errIllegalInvocation)); | 326 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
336 } | 327 } |
337 return this[_closedPromise]; | 328 return this[_closedPromise]; |
338 } | 329 } |
339 | 330 |
340 get desiredSize() { | 331 get desiredSize() { |
341 if (!IsWritableStreamDefaultWriter(this)) { | 332 if (!IsWritableStreamDefaultWriter(this)) { |
342 throw new TypeError(errIllegalInvocation); | 333 throw new TypeError(streamErrors.illegalInvocation); |
343 } | 334 } |
344 if (this[_ownerWritableStream] === undefined) { | 335 if (this[_ownerWritableStream] === undefined) { |
345 throw createWriterLockReleasedError(verbUsedToGetTheDesiredSize); | 336 throw createWriterLockReleasedError(verbUsedToGetTheDesiredSize); |
346 } | 337 } |
347 return WritableStreamDefaultWriterGetDesiredSize(this); | 338 return WritableStreamDefaultWriterGetDesiredSize(this); |
348 } | 339 } |
349 | 340 |
350 get ready() { | 341 get ready() { |
351 if (!IsWritableStreamDefaultWriter(this)) { | 342 if (!IsWritableStreamDefaultWriter(this)) { |
352 return Promise_reject(new TypeError(errIllegalInvocation)); | 343 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
353 } | 344 } |
354 return this[_readyPromise]; | 345 return this[_readyPromise]; |
355 } | 346 } |
356 | 347 |
357 abort(reason) { | 348 abort(reason) { |
358 if (!IsWritableStreamDefaultWriter(this)) { | 349 if (!IsWritableStreamDefaultWriter(this)) { |
359 return Promise_reject(new TypeError(errIllegalInvocation)); | 350 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
360 } | 351 } |
361 if (this[_ownerWritableStream] === undefined) { | 352 if (this[_ownerWritableStream] === undefined) { |
362 return Promise_reject(createWriterLockReleasedError(verbAborted)); | 353 return Promise_reject(createWriterLockReleasedError(verbAborted)); |
363 } | 354 } |
364 return WritableStreamDefaultWriterAbort(this, reason); | 355 return WritableStreamDefaultWriterAbort(this, reason); |
365 } | 356 } |
366 | 357 |
367 close() { | 358 close() { |
368 if (!IsWritableStreamDefaultWriter(this)) { | 359 if (!IsWritableStreamDefaultWriter(this)) { |
369 return Promise_reject(new TypeError(errIllegalInvocation)); | 360 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
370 } | 361 } |
371 const stream = this[_ownerWritableStream]; | 362 const stream = this[_ownerWritableStream]; |
372 if (stream === undefined) { | 363 if (stream === undefined) { |
373 return Promise_reject(createWriterLockReleasedError(verbClosed)); | 364 return Promise_reject(createWriterLockReleasedError(verbClosed)); |
374 } | 365 } |
375 if (stream[_state] === CLOSING) { | 366 if (stream[_state] === CLOSING) { |
376 return Promise_reject(new TypeError(errCloseCloseRequestedStream)); | 367 return Promise_reject(new TypeError(errCloseCloseRequestedStream)); |
377 } | 368 } |
378 return WritableStreamDefaultWriterClose(this); | 369 return WritableStreamDefaultWriterClose(this); |
379 } | 370 } |
380 | 371 |
381 releaseLock() { | 372 releaseLock() { |
382 if (!IsWritableStreamDefaultWriter(this)) { | 373 if (!IsWritableStreamDefaultWriter(this)) { |
383 throw new TypeError(errIllegalInvocation); | 374 throw new TypeError(streamErrors.illegalInvocation); |
384 } | 375 } |
385 const stream = this[_ownerWritableStream]; | 376 const stream = this[_ownerWritableStream]; |
386 if (stream === undefined) { | 377 if (stream === undefined) { |
387 return; | 378 return; |
388 } | 379 } |
389 TEMP_ASSERT(stream[_writer] !== undefined, | 380 TEMP_ASSERT(stream[_writer] !== undefined, |
390 'stream.[[writer]] is not undefined.'); | 381 'stream.[[writer]] is not undefined.'); |
391 WritableStreamDefaultWriterRelease(this); | 382 WritableStreamDefaultWriterRelease(this); |
392 } | 383 } |
393 | 384 |
394 write(chunk) { | 385 write(chunk) { |
395 if (!IsWritableStreamDefaultWriter(this)) { | 386 if (!IsWritableStreamDefaultWriter(this)) { |
396 return Promise_reject(new TypeError(errIllegalInvocation)); | 387 return Promise_reject(new TypeError(streamErrors.illegalInvocation)); |
397 } | 388 } |
398 const stream = this[_ownerWritableStream]; | 389 const stream = this[_ownerWritableStream]; |
399 if (stream === undefined) { | 390 if (stream === undefined) { |
400 return Promise_reject(createWriterLockReleasedError(verbWrittenTo)); | 391 return Promise_reject(createWriterLockReleasedError(verbWrittenTo)); |
401 } | 392 } |
402 if (stream[_state] === CLOSING) { | 393 if (stream[_state] === CLOSING) { |
403 return Promise_reject(new TypeError(errWriteCloseRequestedStream)); | 394 return Promise_reject(new TypeError(errWriteCloseRequestedStream)); |
404 } | 395 } |
405 return WritableStreamDefaultWriterWrite(this, chunk); | 396 return WritableStreamDefaultWriterWrite(this, chunk); |
406 } | 397 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 'state is "writable".'); | 481 'state is "writable".'); |
491 const promise = WritableStreamAddWriteRequest(stream); | 482 const promise = WritableStreamAddWriteRequest(stream); |
492 WritableStreamDefaultControllerWrite(stream[_writableStreamController], | 483 WritableStreamDefaultControllerWrite(stream[_writableStreamController], |
493 chunk); | 484 chunk); |
494 return promise; | 485 return promise; |
495 } | 486 } |
496 | 487 |
497 class WritableStreamDefaultController { | 488 class WritableStreamDefaultController { |
498 constructor(stream, underlyingSink, size, highWaterMark) { | 489 constructor(stream, underlyingSink, size, highWaterMark) { |
499 if (!IsWritableStream(stream)) { | 490 if (!IsWritableStream(stream)) { |
500 throw new TypeError(errIllegalConstructor); | 491 throw new TypeError(streamErrors.illegalConstructor); |
501 } | 492 } |
502 if (stream[_writableStreamController] !== undefined) { | 493 if (stream[_writableStreamController] !== undefined) { |
503 throw new TypeError(errIllegalConstructor); | 494 throw new TypeError(streamErrors.illegalConstructor); |
504 } | 495 } |
505 this[_controlledWritableStream] = stream; | 496 this[_controlledWritableStream] = stream; |
506 this[_underlyingSink] = underlyingSink; | 497 this[_underlyingSink] = underlyingSink; |
507 this[_queue] = new v8.InternalPackedArray(); | 498 this[_queue] = new v8.InternalPackedArray(); |
508 this[_queueSize] = 0; | 499 this[_queueSize] = 0; |
509 this[_defaultControllerFlags] = 0; | 500 this[_defaultControllerFlags] = 0; |
510 const normalizedStrategy = | 501 const normalizedStrategy = |
511 ValidateAndNormalizeQueuingStrategy(size, highWaterMark); | 502 ValidateAndNormalizeQueuingStrategy(size, highWaterMark); |
512 this[_strategySize] = normalizedStrategy.size; | 503 this[_strategySize] = normalizedStrategy.size; |
513 this[_strategyHWM] = normalizedStrategy.highWaterMark; | 504 this[_strategyHWM] = normalizedStrategy.highWaterMark; |
514 const backpressure = WritableStreamDefaultControllerGetBackpressure(this); | 505 const backpressure = WritableStreamDefaultControllerGetBackpressure(this); |
515 if (backpressure) { | 506 if (backpressure) { |
516 WritableStreamUpdateBackpressure(stream, backpressure); | 507 WritableStreamUpdateBackpressure(stream, backpressure); |
517 } | 508 } |
518 const controller = this; | 509 const controller = this; |
519 const startResult = InvokeOrNoop(underlyingSink, 'start', [this]); | 510 const startResult = InvokeOrNoop(underlyingSink, 'start', [this]); |
520 const onFulfilled = () => { | 511 const onFulfilled = () => { |
521 setDefaultControllerStartedFlag(controller, true); | 512 setDefaultControllerStartedFlag(controller, true); |
522 WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); | 513 WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); |
523 }; | 514 }; |
524 const onRejected = r => { | 515 const onRejected = r => { |
525 WritableStreamDefaultControllerErrorIfNeeded(controller, r); | 516 WritableStreamDefaultControllerErrorIfNeeded(controller, r); |
526 }; | 517 }; |
527 thenPromise(Promise_resolve(startResult), onFulfilled, onRejected); | 518 thenPromise(Promise_resolve(startResult), onFulfilled, onRejected); |
528 } | 519 } |
529 | 520 |
530 error(e) { | 521 error(e) { |
531 if (!IsWritableStreamDefaultController(this)) { | 522 if (!IsWritableStreamDefaultController(this)) { |
532 throw new TypeError(errIllegalInvocation); | 523 throw new TypeError(streamErrors.illegalInvocation); |
533 } | 524 } |
534 const state = this[_controlledWritableStream][_state]; | 525 const state = this[_controlledWritableStream][_state]; |
535 if (state === CLOSED || state === ERRORED) { | 526 if (state === CLOSED || state === ERRORED) { |
536 throw createCannotActionOnStateStreamError('error', state); | 527 throw createCannotActionOnStateStreamError('error', state); |
537 } | 528 } |
538 WritableStreamDefaultControllerError(this, e); | 529 WritableStreamDefaultControllerError(this, e); |
539 } | 530 } |
540 } | 531 } |
541 | 532 |
542 // Writable Stream Default Controller Abstract Operations | 533 // Writable Stream Default Controller Abstract Operations |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 TEMP_ASSERT(controller[_queue].length !== 0, | 697 TEMP_ASSERT(controller[_queue].length !== 0, |
707 'queue is not empty.'); | 698 'queue is not empty.'); |
708 const result = controller[_queue].shift(); | 699 const result = controller[_queue].shift(); |
709 controller[_queueSize] -= result.size; | 700 controller[_queueSize] -= result.size; |
710 return result.value; | 701 return result.value; |
711 } | 702 } |
712 | 703 |
713 function EnqueueValueWithSizeForController(controller, value, size) { | 704 function EnqueueValueWithSizeForController(controller, value, size) { |
714 size = Number(size); | 705 size = Number(size); |
715 if (!IsFiniteNonNegativeNumber(size)) { | 706 if (!IsFiniteNonNegativeNumber(size)) { |
716 throw new RangeError(errInvalidSize); | 707 throw new RangeError(streamErrors.invalidSize); |
717 } | 708 } |
718 | 709 |
719 controller[_queueSize] += size; | 710 controller[_queueSize] += size; |
720 controller[_queue].push({value, size}); | 711 controller[_queue].push({value, size}); |
721 } | 712 } |
722 | 713 |
723 function GetTotalQueueSizeForController(controller) { | 714 function GetTotalQueueSizeForController(controller) { |
724 return controller[_queueSize]; | 715 return controller[_queueSize]; |
725 } | 716 } |
726 | 717 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 try { | 771 try { |
781 return Promise_resolve(InvokeOrNoop(O, P, args)); | 772 return Promise_resolve(InvokeOrNoop(O, P, args)); |
782 } catch (e) { | 773 } catch (e) { |
783 return Promise_reject(e); | 774 return Promise_reject(e); |
784 } | 775 } |
785 } | 776 } |
786 | 777 |
787 // TODO(ricea): Share this operation with ReadableStream.js. | 778 // TODO(ricea): Share this operation with ReadableStream.js. |
788 function ValidateAndNormalizeQueuingStrategy(size, highWaterMark) { | 779 function ValidateAndNormalizeQueuingStrategy(size, highWaterMark) { |
789 if (size !== undefined && typeof size !== 'function') { | 780 if (size !== undefined && typeof size !== 'function') { |
790 throw new TypeError(errSizeNotAFunction); | 781 throw new TypeError(streamErrors.sizeNotAFunction); |
791 } | 782 } |
792 | 783 |
793 highWaterMark = Number(highWaterMark); | 784 highWaterMark = Number(highWaterMark); |
794 if (Number_isNaN(highWaterMark) || highWaterMark < 0) { | 785 if (Number_isNaN(highWaterMark)) { |
795 throw new RangeError(errInvalidHWM); | 786 throw new RangeError(streamErrors.errInvalidHWM); |
| 787 } |
| 788 if (highWaterMark < 0) { |
| 789 throw new RangeError(streamErrors.invalidHWM); |
796 } | 790 } |
797 | 791 |
798 return {size, highWaterMark}; | 792 return {size, highWaterMark}; |
799 } | 793 } |
800 | 794 |
801 // | 795 // |
802 // Additions to the global object | 796 // Additions to the global object |
803 // | 797 // |
804 | 798 |
805 defineProperty(global, 'WritableStream', { | 799 defineProperty(global, 'WritableStream', { |
806 value: WritableStream, | 800 value: WritableStream, |
807 enumerable: false, | 801 enumerable: false, |
808 configurable: true, | 802 configurable: true, |
809 writable: true | 803 writable: true |
810 }); | 804 }); |
811 | 805 |
812 // TODO(ricea): Exports to Blink | 806 // TODO(ricea): Exports to Blink |
813 }); | 807 }); |
OLD | NEW |