mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
920138cd5c
Differential Revision: https://phabricator.services.mozilla.com/D172410
545 lines
20 KiB
C++
545 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/dom/WritableStreamDefaultWriter.h"
|
|
#include "js/Array.h"
|
|
#include "js/TypeDecls.h"
|
|
#include "js/Value.h"
|
|
#include "mozilla/AlreadyAddRefed.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/CycleCollectedJSContext.h"
|
|
#include "mozilla/HoldDropJSObjects.h"
|
|
#include "mozilla/dom/WritableStream.h"
|
|
#include "mozilla/dom/WritableStreamDefaultWriterBinding.h"
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "mozilla/dom/Promise-inl.h"
|
|
#include "nsIGlobalObject.h"
|
|
#include "nsISupports.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
using namespace streams_abstract;
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(WritableStreamDefaultWriter)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WritableStreamDefaultWriter)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mStream, mReadyPromise,
|
|
mClosedPromise)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WritableStreamDefaultWriter)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mStream, mReadyPromise,
|
|
mClosedPromise)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WritableStreamDefaultWriter)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(WritableStreamDefaultWriter)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(WritableStreamDefaultWriter)
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WritableStreamDefaultWriter)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
WritableStreamDefaultWriter::WritableStreamDefaultWriter(
|
|
nsIGlobalObject* aGlobal)
|
|
: mGlobal(aGlobal) {
|
|
mozilla::HoldJSObjects(this);
|
|
}
|
|
|
|
WritableStreamDefaultWriter::~WritableStreamDefaultWriter() {
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
void WritableStreamDefaultWriter::SetReadyPromise(Promise* aPromise) {
|
|
MOZ_ASSERT(aPromise);
|
|
mReadyPromise = aPromise;
|
|
}
|
|
|
|
void WritableStreamDefaultWriter::SetClosedPromise(Promise* aPromise) {
|
|
MOZ_ASSERT(aPromise);
|
|
mClosedPromise = aPromise;
|
|
}
|
|
|
|
JSObject* WritableStreamDefaultWriter::WrapObject(
|
|
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
|
|
return WritableStreamDefaultWriter_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
/* static */
|
|
already_AddRefed<WritableStreamDefaultWriter>
|
|
WritableStreamDefaultWriter::Constructor(const GlobalObject& aGlobal,
|
|
WritableStream& aStream,
|
|
ErrorResult& aRv) {
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
RefPtr<WritableStreamDefaultWriter> writer =
|
|
new WritableStreamDefaultWriter(global);
|
|
SetUpWritableStreamDefaultWriter(writer, &aStream, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
return writer.forget();
|
|
}
|
|
|
|
already_AddRefed<Promise> WritableStreamDefaultWriter::Closed() {
|
|
RefPtr<Promise> closedPromise = mClosedPromise;
|
|
return closedPromise.forget();
|
|
}
|
|
|
|
already_AddRefed<Promise> WritableStreamDefaultWriter::Ready() {
|
|
RefPtr<Promise> readyPromise = mReadyPromise;
|
|
return readyPromise.forget();
|
|
}
|
|
|
|
namespace streams_abstract {
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-get-desired-size
|
|
Nullable<double> WritableStreamDefaultWriterGetDesiredSize(
|
|
WritableStreamDefaultWriter* aWriter) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Let state be stream.[[state]].
|
|
WritableStream::WriterState state = stream->State();
|
|
|
|
// Step 3. If state is "errored" or "erroring", return null.
|
|
if (state == WritableStream::WriterState::Errored ||
|
|
state == WritableStream::WriterState::Erroring) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 4. If state is "closed", return 0.
|
|
if (state == WritableStream::WriterState::Closed) {
|
|
return 0.0;
|
|
}
|
|
|
|
// Step 5. Return
|
|
// ! WritableStreamDefaultControllerGetDesiredSize(stream.[[controller]]).
|
|
return stream->Controller()->GetDesiredSize();
|
|
}
|
|
} // namespace streams_abstract
|
|
|
|
// https://streams.spec.whatwg.org/#default-writer-desired-size
|
|
Nullable<double> WritableStreamDefaultWriter::GetDesiredSize(ErrorResult& aRv) {
|
|
// Step 1. If this.[[stream]] is undefined, throw a TypeError exception.
|
|
if (!mStream) {
|
|
aRv.ThrowTypeError("Missing stream");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 2. Return ! WritableStreamDefaultWriterGetDesiredSize(this).
|
|
RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
|
|
return WritableStreamDefaultWriterGetDesiredSize(thisRefPtr);
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-abort
|
|
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WritableStreamDefaultWriterAbort(
|
|
JSContext* aCx, WritableStreamDefaultWriter* aWriter,
|
|
JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Assert: stream is not undefined.
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Step 3. Return ! WritableStreamAbort(stream, reason).
|
|
return WritableStreamAbort(aCx, stream, aReason, aRv);
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#default-writer-abort
|
|
already_AddRefed<Promise> WritableStreamDefaultWriter::Abort(
|
|
JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
|
|
// Step 1. If this.[[stream]] is undefined, return a promise rejected with a
|
|
// TypeError exception.
|
|
if (!mStream) {
|
|
aRv.ThrowTypeError("Missing stream");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 2. Return ! WritableStreamDefaultWriterAbort(this, reason).
|
|
RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
|
|
return WritableStreamDefaultWriterAbort(aCx, thisRefPtr, aReason, aRv);
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-close
|
|
MOZ_CAN_RUN_SCRIPT static already_AddRefed<Promise>
|
|
WritableStreamDefaultWriterClose(JSContext* aCx,
|
|
WritableStreamDefaultWriter* aWriter,
|
|
ErrorResult& aRv) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Assert: stream is not undefined.
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Step 3. Return ! WritableStreamClose(stream).
|
|
return WritableStreamClose(aCx, stream, aRv);
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#default-writer-close
|
|
already_AddRefed<Promise> WritableStreamDefaultWriter::Close(JSContext* aCx,
|
|
ErrorResult& aRv) {
|
|
// Step 1. Let stream be this.[[stream]].
|
|
RefPtr<WritableStream> stream = mStream;
|
|
|
|
// Step 2. If stream is undefined, return a promise rejected with a TypeError
|
|
// exception.
|
|
if (!stream) {
|
|
aRv.ThrowTypeError("Missing stream");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 3. If ! WritableStreamCloseQueuedOrInFlight(stream) is true,
|
|
// return a promise rejected with a TypeError exception.
|
|
if (stream->CloseQueuedOrInFlight()) {
|
|
aRv.ThrowTypeError("Stream is closing");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 3. Return ! WritableStreamDefaultWriterClose(this).
|
|
RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
|
|
return WritableStreamDefaultWriterClose(aCx, thisRefPtr, aRv);
|
|
}
|
|
|
|
namespace streams_abstract {
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-release
|
|
void WritableStreamDefaultWriterRelease(JSContext* aCx,
|
|
WritableStreamDefaultWriter* aWriter) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Assert: stream is not undefined.
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Step 3. Assert: stream.[[writer]] is writer.
|
|
MOZ_ASSERT(stream->GetWriter() == aWriter);
|
|
|
|
// Step 4. Let releasedError be a new TypeError.
|
|
JS::Rooted<JS::Value> releasedError(RootingCx(), JS::UndefinedValue());
|
|
{
|
|
ErrorResult rv;
|
|
rv.ThrowTypeError("Releasing lock");
|
|
bool ok = ToJSValue(aCx, std::move(rv), &releasedError);
|
|
MOZ_RELEASE_ASSERT(ok, "must be ok");
|
|
}
|
|
|
|
// Step 5. Perform !
|
|
// WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer,
|
|
// releasedError).
|
|
WritableStreamDefaultWriterEnsureReadyPromiseRejected(aWriter, releasedError);
|
|
|
|
// Step 6. Perform !
|
|
// WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer,
|
|
// releasedError).
|
|
WritableStreamDefaultWriterEnsureClosedPromiseRejected(aWriter,
|
|
releasedError);
|
|
|
|
// Step 7. Set stream.[[writer]] to undefined.
|
|
stream->SetWriter(nullptr);
|
|
|
|
// Step 8. Set writer.[[stream]] to undefined.
|
|
aWriter->SetStream(nullptr);
|
|
}
|
|
} // namespace streams_abstract
|
|
|
|
// https://streams.spec.whatwg.org/#default-writer-release-lock
|
|
void WritableStreamDefaultWriter::ReleaseLock(JSContext* aCx) {
|
|
// Step 1. Let stream be this.[[stream]].
|
|
RefPtr<WritableStream> stream = mStream;
|
|
|
|
// Step 2. If stream is undefined, return.
|
|
if (!stream) {
|
|
return;
|
|
}
|
|
|
|
// Step 3. Assert: stream.[[writer]] is not undefined.
|
|
MOZ_ASSERT(stream->GetWriter());
|
|
|
|
// Step 4. Perform ! WritableStreamDefaultWriterRelease(this).
|
|
RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
|
|
return WritableStreamDefaultWriterRelease(aCx, thisRefPtr);
|
|
}
|
|
|
|
namespace streams_abstract {
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-write
|
|
already_AddRefed<Promise> WritableStreamDefaultWriterWrite(
|
|
JSContext* aCx, WritableStreamDefaultWriter* aWriter,
|
|
JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Assert: stream is not undefined.
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Step 3. Let controller be stream.[[controller]].
|
|
RefPtr<WritableStreamDefaultController> controller = stream->Controller();
|
|
|
|
// Step 4. Let chunkSize be !
|
|
// WritableStreamDefaultControllerGetChunkSize(controller, chunk).
|
|
double chunkSize =
|
|
WritableStreamDefaultControllerGetChunkSize(aCx, controller, aChunk, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 5. If stream is not equal to writer.[[stream]], return a promise
|
|
// rejected with a TypeError exception.
|
|
if (stream != aWriter->GetStream()) {
|
|
aRv.ThrowTypeError(
|
|
"Can not write on WritableStream owned by another writer.");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 6. Let state be stream.[[state]].
|
|
WritableStream::WriterState state = stream->State();
|
|
|
|
// Step 7. If state is "errored", return a promise rejected with
|
|
// stream.[[storedError]].
|
|
if (state == WritableStream::WriterState::Errored) {
|
|
JS::Rooted<JS::Value> error(aCx, stream->StoredError());
|
|
return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
|
|
}
|
|
|
|
// Step 8. If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state
|
|
// is "closed", return a promise rejected with a TypeError exception
|
|
// indicating that the stream is closing or closed.
|
|
if (stream->CloseQueuedOrInFlight() ||
|
|
state == WritableStream::WriterState::Closed) {
|
|
return Promise::CreateRejectedWithTypeError(
|
|
aWriter->GetParentObject(), "Stream is closed or closing"_ns, aRv);
|
|
}
|
|
|
|
// Step 9. If state is "erroring", return a promise rejected with
|
|
// stream.[[storedError]].
|
|
if (state == WritableStream::WriterState::Erroring) {
|
|
JS::Rooted<JS::Value> error(aCx, stream->StoredError());
|
|
return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
|
|
}
|
|
|
|
// Step 10. Assert: state is "writable".
|
|
MOZ_ASSERT(state == WritableStream::WriterState::Writable);
|
|
|
|
// Step 11. Let promise be ! WritableStreamAddWriteRequest(stream).
|
|
RefPtr<Promise> promise = WritableStreamAddWriteRequest(stream);
|
|
|
|
// Step 12. Perform ! WritableStreamDefaultControllerWrite(controller, chunk,
|
|
// chunkSize).
|
|
WritableStreamDefaultControllerWrite(aCx, controller, aChunk, chunkSize, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 13. Return promise.
|
|
return promise.forget();
|
|
}
|
|
} // namespace streams_abstract
|
|
|
|
// https://streams.spec.whatwg.org/#default-writer-write
|
|
already_AddRefed<Promise> WritableStreamDefaultWriter::Write(
|
|
JSContext* aCx, JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
|
|
// Step 1. If this.[[stream]] is undefined, return a promise rejected with a
|
|
// TypeError exception.
|
|
if (!mStream) {
|
|
aRv.ThrowTypeError("Missing stream");
|
|
return nullptr;
|
|
}
|
|
|
|
// Step 2. Return ! WritableStreamDefaultWriterWrite(this, chunk).
|
|
return WritableStreamDefaultWriterWrite(aCx, this, aChunk, aRv);
|
|
}
|
|
|
|
namespace streams_abstract {
|
|
|
|
// https://streams.spec.whatwg.org/#set-up-writable-stream-default-writer
|
|
void SetUpWritableStreamDefaultWriter(WritableStreamDefaultWriter* aWriter,
|
|
WritableStream* aStream,
|
|
ErrorResult& aRv) {
|
|
// Step 1. If ! IsWritableStreamLocked(stream) is true, throw a TypeError
|
|
// exception.
|
|
if (IsWritableStreamLocked(aStream)) {
|
|
aRv.ThrowTypeError("WritableStream is already locked!");
|
|
return;
|
|
}
|
|
|
|
// Step 2. Set writer.[[stream]] to stream.
|
|
aWriter->SetStream(aStream);
|
|
|
|
// Step 3. Set stream.[[writer]] to writer.
|
|
aStream->SetWriter(aWriter);
|
|
|
|
// Step 4. Let state be stream.[[state]].
|
|
WritableStream::WriterState state = aStream->State();
|
|
|
|
// Step 5. If state is "writable",
|
|
if (state == WritableStream::WriterState::Writable) {
|
|
RefPtr<Promise> readyPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
|
|
// Step 5.1 If ! WritableStreamCloseQueuedOrInFlight(stream) is false and
|
|
// stream.[[backpressure]] is true, set writer.[[readyPromise]] to a new
|
|
// promise.
|
|
if (!aStream->CloseQueuedOrInFlight() && aStream->Backpressure()) {
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
} else {
|
|
// Step 5.2. Otherwise, set writer.[[readyPromise]] to a promise resolved
|
|
// with undefined.
|
|
readyPromise->MaybeResolveWithUndefined();
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
}
|
|
|
|
// Step 5.3. Set writer.[[closedPromise]] to a new promise.
|
|
RefPtr<Promise> closedPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
aWriter->SetClosedPromise(closedPromise);
|
|
} else if (state == WritableStream::WriterState::Erroring) {
|
|
// Step 6. Otherwise, if state is "erroring",
|
|
|
|
// Step 6.1. Set writer.[[readyPromise]] to a promise rejected with
|
|
// stream.[[storedError]].
|
|
JS::Rooted<JS::Value> storedError(RootingCx(), aStream->StoredError());
|
|
RefPtr<Promise> readyPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
readyPromise->MaybeReject(storedError);
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
|
|
// Step 6.2. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
|
|
readyPromise->SetSettledPromiseIsHandled();
|
|
|
|
// Step 6.3. Set writer.[[closedPromise]] to a new promise.
|
|
RefPtr<Promise> closedPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
aWriter->SetClosedPromise(closedPromise);
|
|
} else if (state == WritableStream::WriterState::Closed) {
|
|
// Step 7. Otherwise, if state is "closed",
|
|
// Step 7.1. Set writer.[[readyPromise]] to a promise resolved with
|
|
// undefined.
|
|
RefPtr<Promise> readyPromise =
|
|
Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(), aRv);
|
|
if (aRv.Failed()) {
|
|
return;
|
|
}
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
|
|
// Step 7.2. Set writer.[[closedPromise]] to a promise resolved with
|
|
// undefined.
|
|
RefPtr<Promise> closedPromise =
|
|
Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(), aRv);
|
|
if (aRv.Failed()) {
|
|
return;
|
|
}
|
|
aWriter->SetClosedPromise(closedPromise);
|
|
} else {
|
|
// Step 8. Otherwise,
|
|
// Step 8.1 Assert: state is "errored".
|
|
MOZ_ASSERT(state == WritableStream::WriterState::Errored);
|
|
|
|
// Step 8.2. Step Let storedError be stream.[[storedError]].
|
|
JS::Rooted<JS::Value> storedError(RootingCx(), aStream->StoredError());
|
|
|
|
// Step 8.3. Set writer.[[readyPromise]] to a promise rejected with
|
|
// storedError.
|
|
RefPtr<Promise> readyPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
readyPromise->MaybeReject(storedError);
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
|
|
// Step 8.4. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
|
|
readyPromise->SetSettledPromiseIsHandled();
|
|
|
|
// Step 8.5. Set writer.[[closedPromise]] to a promise rejected with
|
|
// storedError.
|
|
RefPtr<Promise> closedPromise =
|
|
Promise::CreateInfallible(aWriter->GetParentObject());
|
|
closedPromise->MaybeReject(storedError);
|
|
aWriter->SetClosedPromise(closedPromise);
|
|
|
|
// Step 8.6 Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
|
|
closedPromise->SetSettledPromiseIsHandled();
|
|
}
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-closed-promise-rejected
|
|
void WritableStreamDefaultWriterEnsureClosedPromiseRejected(
|
|
WritableStreamDefaultWriter* aWriter, JS::Handle<JS::Value> aError) {
|
|
RefPtr<Promise> closedPromise = aWriter->ClosedPromise();
|
|
// Step 1. If writer.[[closedPromise]].[[PromiseState]] is "pending", reject
|
|
// writer.[[closedPromise]] with error.
|
|
if (closedPromise->State() == Promise::PromiseState::Pending) {
|
|
closedPromise->MaybeReject(aError);
|
|
} else {
|
|
// Step 2. Otherwise, set writer.[[closedPromise]] to a promise rejected
|
|
// with error.
|
|
closedPromise = Promise::CreateInfallible(aWriter->GetParentObject());
|
|
closedPromise->MaybeReject(aError);
|
|
aWriter->SetClosedPromise(closedPromise);
|
|
}
|
|
|
|
// Step 3. Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
|
|
closedPromise->SetSettledPromiseIsHandled();
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-ready-promise-rejected
|
|
void WritableStreamDefaultWriterEnsureReadyPromiseRejected(
|
|
WritableStreamDefaultWriter* aWriter, JS::Handle<JS::Value> aError) {
|
|
RefPtr<Promise> readyPromise = aWriter->ReadyPromise();
|
|
// Step 1. If writer.[[readyPromise]].[[PromiseState]] is "pending", reject
|
|
// writer.[[readyPromise]] with error.
|
|
if (readyPromise->State() == Promise::PromiseState::Pending) {
|
|
readyPromise->MaybeReject(aError);
|
|
} else {
|
|
// Step 2. Otherwise, set writer.[[readyPromise]] to a promise rejected with
|
|
// error.
|
|
readyPromise = Promise::CreateInfallible(aWriter->GetParentObject());
|
|
readyPromise->MaybeReject(aError);
|
|
aWriter->SetReadyPromise(readyPromise);
|
|
}
|
|
|
|
// Step 3. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
|
|
readyPromise->SetSettledPromiseIsHandled();
|
|
}
|
|
|
|
// https://streams.spec.whatwg.org/#writable-stream-default-writer-close-with-error-propagation
|
|
already_AddRefed<Promise> WritableStreamDefaultWriterCloseWithErrorPropagation(
|
|
JSContext* aCx, WritableStreamDefaultWriter* aWriter, ErrorResult& aRv) {
|
|
// Step 1. Let stream be writer.[[stream]].
|
|
RefPtr<WritableStream> stream = aWriter->GetStream();
|
|
|
|
// Step 2. Assert: stream is not undefined.
|
|
MOZ_ASSERT(stream);
|
|
|
|
// Step 3. Let state be stream.[[state]].
|
|
WritableStream::WriterState state = stream->State();
|
|
|
|
// Step 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is true
|
|
// or state is "closed", return a promise resolved with undefined.
|
|
if (stream->CloseQueuedOrInFlight() ||
|
|
state == WritableStream::WriterState::Closed) {
|
|
return Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(),
|
|
aRv);
|
|
}
|
|
|
|
// Step 5. If state is "errored",
|
|
// return a promise rejected with stream.[[storedError]].
|
|
if (state == WritableStream::WriterState::Errored) {
|
|
JS::Rooted<JS::Value> error(aCx, stream->StoredError());
|
|
return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
|
|
}
|
|
|
|
// Step 6. Assert: state is "writable" or "erroring".
|
|
MOZ_ASSERT(state == WritableStream::WriterState::Writable ||
|
|
state == WritableStream::WriterState::Erroring);
|
|
|
|
// Step 7. Return ! WritableStreamDefaultWriterClose(writer).
|
|
return WritableStreamDefaultWriterClose(aCx, aWriter, aRv);
|
|
}
|
|
|
|
} // namespace streams_abstract
|
|
|
|
} // namespace mozilla::dom
|