зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1582348 - Implement WritableStreamClose and WritableStream.prototype.close. r=arai
Differential Revision: https://phabricator.services.mozilla.com/D51965 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
698a44f25e
Коммит
ab41b023a0
|
@ -19,7 +19,7 @@
|
||||||
#include "builtin/streams/MiscellaneousOperations.h" // js::MakeSizeAlgorithmFromSizeFunction, js::ReturnPromiseRejectedWithPendingError, js::ValidateAndNormalizeHighWaterMark
|
#include "builtin/streams/MiscellaneousOperations.h" // js::MakeSizeAlgorithmFromSizeFunction, js::ReturnPromiseRejectedWithPendingError, js::ValidateAndNormalizeHighWaterMark
|
||||||
#include "builtin/streams/WritableStreamDefaultControllerOperations.h" // js::SetUpWritableStreamDefaultControllerFromUnderlyingSink
|
#include "builtin/streams/WritableStreamDefaultControllerOperations.h" // js::SetUpWritableStreamDefaultControllerFromUnderlyingSink
|
||||||
#include "builtin/streams/WritableStreamDefaultWriter.h" // js::CreateWritableStreamDefaultWriter
|
#include "builtin/streams/WritableStreamDefaultWriter.h" // js::CreateWritableStreamDefaultWriter
|
||||||
#include "builtin/streams/WritableStreamOperations.h" // js::WritableStreamAbort
|
#include "builtin/streams/WritableStreamOperations.h" // js::WritableStream{Abort,Close{,QueuedOrInFlight}}
|
||||||
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
|
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
|
||||||
#include "js/Class.h" // JS{Function,Property}Spec, JS_{FS,PS}_END, JSCLASS_PRIVATE_IS_NSISUPPORTS, JSCLASS_HAS_PRIVATE, JS_NULL_CLASS_OPS
|
#include "js/Class.h" // JS{Function,Property}Spec, JS_{FS,PS}_END, JSCLASS_PRIVATE_IS_NSISUPPORTS, JSCLASS_HAS_PRIVATE, JS_NULL_CLASS_OPS
|
||||||
#include "js/RealmOptions.h" // JS::RealmCreationOptions
|
#include "js/RealmOptions.h" // JS::RealmCreationOptions
|
||||||
|
@ -42,6 +42,8 @@ using js::ReturnPromiseRejectedWithPendingError;
|
||||||
using js::UnwrapAndTypeCheckThis;
|
using js::UnwrapAndTypeCheckThis;
|
||||||
using js::WritableStream;
|
using js::WritableStream;
|
||||||
using js::WritableStreamAbort;
|
using js::WritableStreamAbort;
|
||||||
|
using js::WritableStreamClose;
|
||||||
|
using js::WritableStreamCloseQueuedOrInFlight;
|
||||||
|
|
||||||
using JS::CallArgs;
|
using JS::CallArgs;
|
||||||
using JS::CallArgsFromVp;
|
using JS::CallArgsFromVp;
|
||||||
|
@ -189,7 +191,7 @@ static bool WritableStream_abort(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
// rejected with a TypeError exception.
|
// rejected with a TypeError exception.
|
||||||
if (unwrappedStream->isLocked()) {
|
if (unwrappedStream->isLocked()) {
|
||||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||||
JSMSG_CANT_ABORT_LOCKED_WRITABLESTREAM);
|
JSMSG_CANT_USE_LOCKED_WRITABLESTREAM, "abort");
|
||||||
return ReturnPromiseRejectedWithPendingError(cx, args);
|
return ReturnPromiseRejectedWithPendingError(cx, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +207,47 @@ static bool WritableStream_abort(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams spec, 4.2.5.3. getWriter()
|
* Streams spec, 4.2.5.3. close()
|
||||||
|
*/
|
||||||
|
static bool WritableStream_close(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1: If ! IsWritableStream(this) is false, return a promise rejected
|
||||||
|
// with a TypeError exception.
|
||||||
|
Rooted<WritableStream*> unwrappedStream(
|
||||||
|
cx, UnwrapAndTypeCheckThis<WritableStream>(cx, args, "close"));
|
||||||
|
if (!unwrappedStream) {
|
||||||
|
return ReturnPromiseRejectedWithPendingError(cx, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: If ! IsWritableStreamLocked(this) is true, return a promise
|
||||||
|
// rejected with a TypeError exception.
|
||||||
|
if (unwrappedStream->isLocked()) {
|
||||||
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||||
|
JSMSG_CANT_USE_LOCKED_WRITABLESTREAM, "close");
|
||||||
|
return ReturnPromiseRejectedWithPendingError(cx, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a
|
||||||
|
// promise rejected with a TypeError exception.
|
||||||
|
if (WritableStreamCloseQueuedOrInFlight(unwrappedStream)) {
|
||||||
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||||
|
JSMSG_WRITABLESTREAM_CLOSE_CLOSING_OR_CLOSED);
|
||||||
|
return ReturnPromiseRejectedWithPendingError(cx, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Return ! WritableStreamClose(this).
|
||||||
|
JSObject* promise = WritableStreamClose(cx, unwrappedStream);
|
||||||
|
if (!promise) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.rval().setObject(*promise);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streams spec, 4.2.5.4. getWriter()
|
||||||
*/
|
*/
|
||||||
static bool WritableStream_getWriter(JSContext* cx, unsigned argc, Value* vp) {
|
static bool WritableStream_getWriter(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
@ -228,6 +270,7 @@ static bool WritableStream_getWriter(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
static const JSFunctionSpec WritableStream_methods[] = {
|
static const JSFunctionSpec WritableStream_methods[] = {
|
||||||
JS_FN("abort", WritableStream_abort, 1, 0),
|
JS_FN("abort", WritableStream_abort, 1, 0),
|
||||||
|
JS_FN("close", WritableStream_close, 0, 0),
|
||||||
JS_FN("getWriter", WritableStream_getWriter, 0, 0), JS_FS_END};
|
JS_FN("getWriter", WritableStream_getWriter, 0, 0), JS_FS_END};
|
||||||
|
|
||||||
static const JSPropertySpec WritableStream_properties[] = {
|
static const JSPropertySpec WritableStream_properties[] = {
|
||||||
|
|
|
@ -14,10 +14,12 @@
|
||||||
#include <stdint.h> // uint32_t
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
#include "jsapi.h" // JS_ReportErrorASCII, JS_SetPrivate
|
#include "jsapi.h" // JS_ReportErrorASCII, JS_SetPrivate
|
||||||
|
#include "jsfriendapi.h" // js::GetErrorMessage, JSMSG_*
|
||||||
|
|
||||||
#include "builtin/Promise.h" // js::PromiseObject
|
#include "builtin/Promise.h" // js::PromiseObject
|
||||||
|
#include "builtin/streams/MiscellaneousOperations.h" // js::PromiseRejectedWithPendingError
|
||||||
#include "builtin/streams/WritableStream.h" // js::WritableStream
|
#include "builtin/streams/WritableStream.h" // js::WritableStream
|
||||||
#include "builtin/streams/WritableStreamDefaultController.h" // js::WritableStreamDefaultController, js::WritableStream::controller
|
#include "builtin/streams/WritableStreamDefaultController.h" // js::WritableStreamDefaultController{,Close}, js::WritableStream::controller
|
||||||
#include "builtin/streams/WritableStreamDefaultControllerOperations.h" // js::WritableStreamControllerErrorSteps
|
#include "builtin/streams/WritableStreamDefaultControllerOperations.h" // js::WritableStreamControllerErrorSteps
|
||||||
#include "builtin/streams/WritableStreamWriterOperations.h" // js::WritableStreamDefaultWriterEnsureReadyPromiseRejected
|
#include "builtin/streams/WritableStreamWriterOperations.h" // js::WritableStreamDefaultWriterEnsureReadyPromiseRejected
|
||||||
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
|
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
|
||||||
|
@ -197,6 +199,78 @@ JSObject* js::WritableStreamAbort(JSContext* cx,
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streams spec, 4.3.7.
|
||||||
|
* WritableStreamClose ( stream )
|
||||||
|
*
|
||||||
|
* Note: The object (a promise) returned by this function is in the current
|
||||||
|
* compartment and does not require special wrapping to be put to use.
|
||||||
|
*/
|
||||||
|
JSObject* js::WritableStreamClose(JSContext* cx,
|
||||||
|
Handle<WritableStream*> unwrappedStream) {
|
||||||
|
// Step 1: Let state be stream.[[state]].
|
||||||
|
// Step 2: If state is "closed" or "errored", return a promise rejected with a
|
||||||
|
// TypeError exception.
|
||||||
|
if (unwrappedStream->closed() || unwrappedStream->errored()) {
|
||||||
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||||
|
JSMSG_WRITABLESTREAM_CLOSED_OR_ERRORED);
|
||||||
|
return PromiseRejectedWithPendingError(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Assert: state is "writable" or "erroring".
|
||||||
|
MOZ_ASSERT(unwrappedStream->writable() ^ unwrappedStream->erroring());
|
||||||
|
|
||||||
|
// Step 4: Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false.
|
||||||
|
MOZ_ASSERT(!WritableStreamCloseQueuedOrInFlight(unwrappedStream));
|
||||||
|
|
||||||
|
// Step 5: Let promise be a new promise.
|
||||||
|
Rooted<PromiseObject*> promise(cx, PromiseObject::createSkippingExecutor(cx));
|
||||||
|
if (!promise) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Set stream.[[closeRequest]] to promise.
|
||||||
|
{
|
||||||
|
AutoRealm ar(cx, unwrappedStream);
|
||||||
|
Rooted<JSObject*> wrappedPromise(cx, promise);
|
||||||
|
if (!cx->compartment()->wrap(cx, &wrappedPromise)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unwrappedStream->setCloseRequest(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Let writer be stream.[[writer]].
|
||||||
|
// Step 8: If writer is not undefined, and stream.[[backpressure]] is true,
|
||||||
|
// and state is "writable", resolve writer.[[readyPromise]] with
|
||||||
|
// undefined.
|
||||||
|
if (unwrappedStream->hasWriter() && unwrappedStream->backpressure() &&
|
||||||
|
unwrappedStream->writable()) {
|
||||||
|
Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
|
||||||
|
cx, UnwrapWriterFromStream(cx, unwrappedStream));
|
||||||
|
if (!unwrappedWriter) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ResolveUnwrappedPromiseWithUndefined(
|
||||||
|
cx, unwrappedWriter->readyPromise())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9: Perform
|
||||||
|
// ! WritableStreamDefaultControllerClose(
|
||||||
|
// stream.[[writableStreamController]]).
|
||||||
|
Rooted<WritableStreamDefaultController*> unwrappedController(
|
||||||
|
cx, unwrappedStream->controller());
|
||||||
|
if (!WritableStreamDefaultControllerClose(cx, unwrappedController)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 10: Return promise.
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
/*** 4.4. Writable stream abstract operations used by controllers ***********/
|
/*** 4.4. Writable stream abstract operations used by controllers ***********/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,6 +26,9 @@ extern JSObject* WritableStreamAbort(
|
||||||
JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
|
JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
|
||||||
JS::Handle<JS::Value> reason);
|
JS::Handle<JS::Value> reason);
|
||||||
|
|
||||||
|
extern JSObject* WritableStreamClose(
|
||||||
|
JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
|
||||||
|
|
||||||
extern MOZ_MUST_USE PromiseObject* WritableStreamAddWriteRequest(
|
extern MOZ_MUST_USE PromiseObject* WritableStreamAddWriteRequest(
|
||||||
JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
|
JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
|
||||||
|
|
||||||
|
|
|
@ -689,7 +689,7 @@ MSG_DEF(JSMSG_WRITABLESTREAMWRITER_NOT_OWNED, 1, JSEXN_TYPEERR, "the
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_CLOSED_OR_ERRORED, 0, JSEXN_TYPEERR, "writable stream is already closed or errored")
|
MSG_DEF(JSMSG_WRITABLESTREAM_CLOSED_OR_ERRORED, 0, JSEXN_TYPEERR, "writable stream is already closed or errored")
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_RELEASED_DURING_WRITE, 0, JSEXN_TYPEERR, "writer's lock on the stream was released before writing completed")
|
MSG_DEF(JSMSG_WRITABLESTREAM_RELEASED_DURING_WRITE, 0, JSEXN_TYPEERR, "writer's lock on the stream was released before writing completed")
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_WRITE_CLOSING_OR_CLOSED, 0, JSEXN_TYPEERR, "can't write to a stream that's currently closing or already closed")
|
MSG_DEF(JSMSG_WRITABLESTREAM_WRITE_CLOSING_OR_CLOSED, 0, JSEXN_TYPEERR, "can't write to a stream that's currently closing or already closed")
|
||||||
MSG_DEF(JSMSG_CANT_ABORT_LOCKED_WRITABLESTREAM, 0, JSEXN_TYPEERR, "can't abort a WritableStream that's locked to a writer")
|
MSG_DEF(JSMSG_CANT_USE_LOCKED_WRITABLESTREAM, 1, JSEXN_TYPEERR, "can't {0} a WritableStream that's locked to a writer")
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_CLOSE_CLOSING_OR_CLOSED, 0, JSEXN_TYPEERR, "can't close a stream that's currently closing or already closed")
|
MSG_DEF(JSMSG_WRITABLESTREAM_CLOSE_CLOSING_OR_CLOSED, 0, JSEXN_TYPEERR, "can't close a stream that's currently closing or already closed")
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_CANT_RELEASE_ALREADY_CLOSED,0, JSEXN_TYPEERR, "writer has already been released and can't be closed")
|
MSG_DEF(JSMSG_WRITABLESTREAM_CANT_RELEASE_ALREADY_CLOSED,0, JSEXN_TYPEERR, "writer has already been released and can't be closed")
|
||||||
MSG_DEF(JSMSG_WRITABLESTREAM_ALREADY_LOCKED, 0, JSEXN_TYPEERR, "writable stream is already locked by another writer")
|
MSG_DEF(JSMSG_WRITABLESTREAM_ALREADY_LOCKED, 0, JSEXN_TYPEERR, "writable stream is already locked by another writer")
|
||||||
|
|
Загрузка…
Ссылка в новой задаче