summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/streams/ReadableStreamDefaultReader.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/builtin/streams/ReadableStreamDefaultReader.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/builtin/streams/ReadableStreamDefaultReader.cpp')
-rw-r--r--js/src/builtin/streams/ReadableStreamDefaultReader.cpp265
1 files changed, 265 insertions, 0 deletions
diff --git a/js/src/builtin/streams/ReadableStreamDefaultReader.cpp b/js/src/builtin/streams/ReadableStreamDefaultReader.cpp
new file mode 100644
index 0000000000..cf7cda48f6
--- /dev/null
+++ b/js/src/builtin/streams/ReadableStreamDefaultReader.cpp
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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/. */
+
+/* Class ReadableStreamDefaultReader. */
+
+#include "mozilla/Attributes.h" // MOZ_MUST_USE
+
+#include "jsapi.h" // JS_ReportErrorNumberASCII
+
+#include "builtin/streams/ClassSpecMacro.h" // JS_STREAMS_CLASS_SPEC
+#include "builtin/streams/MiscellaneousOperations.h" // js::ReturnPromiseRejectedWithPendingError
+#include "builtin/streams/ReadableStream.h" // js::ReadableStream
+#include "builtin/streams/ReadableStreamReader.h" // js::ForAuthorCodeBool, js::ReadableStream{,Default}Reader
+#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
+#include "js/Class.h" // JSClass, JS_NULL_CLASS_OPS
+#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
+#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
+#include "vm/PromiseObject.h" // js::PromiseObject
+
+#include "vm/Compartment-inl.h" // js::UnwrapAndTypeCheckThis
+#include "vm/JSObject-inl.h" // js::NewObjectWithClassProto
+#include "vm/NativeObject-inl.h" // js::ThrowIfNotConstructing
+
+using JS::CallArgs;
+using JS::CallArgsFromVp;
+using JS::Handle;
+using JS::Rooted;
+using JS::Value;
+
+using js::ForAuthorCodeBool;
+using js::GetErrorMessage;
+using js::ListObject;
+using js::NewObjectWithClassProto;
+using js::PromiseObject;
+using js::ReadableStream;
+using js::ReadableStreamDefaultReader;
+using js::ReadableStreamReader;
+using js::UnwrapAndTypeCheckThis;
+
+/*** 3.6. Class ReadableStreamDefaultReader *********************************/
+
+/**
+ * Stream spec, 3.6.3. new ReadableStreamDefaultReader ( stream )
+ * Steps 2-4.
+ */
+MOZ_MUST_USE ReadableStreamDefaultReader* js::CreateReadableStreamDefaultReader(
+ JSContext* cx, Handle<ReadableStream*> unwrappedStream,
+ ForAuthorCodeBool forAuthorCode, Handle<JSObject*> proto /* = nullptr */) {
+ Rooted<ReadableStreamDefaultReader*> reader(
+ cx, NewObjectWithClassProto<ReadableStreamDefaultReader>(cx, proto));
+ if (!reader) {
+ return nullptr;
+ }
+
+ // Step 2: If ! IsReadableStreamLocked(stream) is true, throw a TypeError
+ // exception.
+ if (unwrappedStream->locked()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_READABLESTREAM_LOCKED);
+ return nullptr;
+ }
+
+ // Step 3: Perform ! ReadableStreamReaderGenericInitialize(this, stream).
+ // Step 4: Set this.[[readRequests]] to a new empty List.
+ if (!ReadableStreamReaderGenericInitialize(cx, reader, unwrappedStream,
+ forAuthorCode)) {
+ return nullptr;
+ }
+
+ return reader;
+}
+
+/**
+ * Stream spec, 3.6.3. new ReadableStreamDefaultReader ( stream )
+ */
+bool ReadableStreamDefaultReader::constructor(JSContext* cx, unsigned argc,
+ Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "ReadableStreamDefaultReader")) {
+ return false;
+ }
+
+ // Implicit in the spec: Find the prototype object to use.
+ Rooted<JSObject*> proto(cx);
+ if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
+ return false;
+ }
+
+ // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError
+ // exception.
+ Rooted<ReadableStream*> unwrappedStream(
+ cx, UnwrapAndTypeCheckArgument<ReadableStream>(
+ cx, args, "ReadableStreamDefaultReader constructor", 0));
+ if (!unwrappedStream) {
+ return false;
+ }
+
+ Rooted<JSObject*> reader(
+ cx, CreateReadableStreamDefaultReader(cx, unwrappedStream,
+ ForAuthorCodeBool::Yes, proto));
+ if (!reader) {
+ return false;
+ }
+
+ args.rval().setObject(*reader);
+ return true;
+}
+
+/**
+ * Streams spec, 3.6.4.1 get closed
+ */
+static MOZ_MUST_USE bool ReadableStreamDefaultReader_closed(JSContext* cx,
+ unsigned argc,
+ Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
+ // rejected with a TypeError exception.
+ Rooted<ReadableStreamDefaultReader*> unwrappedReader(
+ cx, UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args,
+ "get closed"));
+ if (!unwrappedReader) {
+ return ReturnPromiseRejectedWithPendingError(cx, args);
+ }
+
+ // Step 2: Return this.[[closedPromise]].
+ Rooted<JSObject*> closedPromise(cx, unwrappedReader->closedPromise());
+ if (!cx->compartment()->wrap(cx, &closedPromise)) {
+ return false;
+ }
+
+ args.rval().setObject(*closedPromise);
+ return true;
+}
+
+/**
+ * Streams spec, 3.6.4.2. cancel ( reason )
+ */
+static MOZ_MUST_USE bool ReadableStreamDefaultReader_cancel(JSContext* cx,
+ unsigned argc,
+ Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
+ // rejected with a TypeError exception.
+ Rooted<ReadableStreamDefaultReader*> unwrappedReader(
+ cx,
+ UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args, "cancel"));
+ if (!unwrappedReader) {
+ return ReturnPromiseRejectedWithPendingError(cx, args);
+ }
+
+ // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise
+ // rejected with a TypeError exception.
+ if (!unwrappedReader->hasStream()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_READABLESTREAMREADER_NOT_OWNED, "cancel");
+ return ReturnPromiseRejectedWithPendingError(cx, args);
+ }
+
+ // Step 3: Return ! ReadableStreamReaderGenericCancel(this, reason).
+ JSObject* cancelPromise =
+ ReadableStreamReaderGenericCancel(cx, unwrappedReader, args.get(0));
+ if (!cancelPromise) {
+ return false;
+ }
+ args.rval().setObject(*cancelPromise);
+ return true;
+}
+
+/**
+ * Streams spec, 3.6.4.3 read ( )
+ */
+static MOZ_MUST_USE bool ReadableStreamDefaultReader_read(JSContext* cx,
+ unsigned argc,
+ Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
+ // rejected with a TypeError exception.
+ Rooted<ReadableStreamDefaultReader*> unwrappedReader(
+ cx,
+ UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args, "read"));
+ if (!unwrappedReader) {
+ return ReturnPromiseRejectedWithPendingError(cx, args);
+ }
+
+ // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise
+ // rejected with a TypeError exception.
+ if (!unwrappedReader->hasStream()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_READABLESTREAMREADER_NOT_OWNED, "read");
+ return ReturnPromiseRejectedWithPendingError(cx, args);
+ }
+
+ // Step 3: Return ! ReadableStreamDefaultReaderRead(this, true).
+ PromiseObject* readPromise =
+ js::ReadableStreamDefaultReaderRead(cx, unwrappedReader);
+ if (!readPromise) {
+ return false;
+ }
+ args.rval().setObject(*readPromise);
+ return true;
+}
+
+/**
+ * Streams spec, 3.6.4.4. releaseLock ( )
+ */
+static bool ReadableStreamDefaultReader_releaseLock(JSContext* cx,
+ unsigned argc, Value* vp) {
+ // Step 1: If ! IsReadableStreamDefaultReader(this) is false,
+ // throw a TypeError exception.
+ CallArgs args = CallArgsFromVp(argc, vp);
+ Rooted<ReadableStreamDefaultReader*> reader(
+ cx, UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args,
+ "releaseLock"));
+ if (!reader) {
+ return false;
+ }
+
+ // Step 2: If this.[[ownerReadableStream]] is undefined, return.
+ if (!reader->hasStream()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Step 3: If this.[[readRequests]] is not empty, throw a TypeError exception.
+ Value val = reader->getFixedSlot(ReadableStreamReader::Slot_Requests);
+ if (!val.isUndefined()) {
+ ListObject* readRequests = &val.toObject().as<ListObject>();
+ if (readRequests->length() != 0) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_READABLESTREAMREADER_NOT_EMPTY,
+ "releaseLock");
+ return false;
+ }
+ }
+
+ // Step 4: Perform ! ReadableStreamReaderGenericRelease(this).
+ if (!js::ReadableStreamReaderGenericRelease(cx, reader)) {
+ return false;
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static const JSFunctionSpec ReadableStreamDefaultReader_methods[] = {
+ JS_FN("cancel", ReadableStreamDefaultReader_cancel, 1, 0),
+ JS_FN("read", ReadableStreamDefaultReader_read, 0, 0),
+ JS_FN("releaseLock", ReadableStreamDefaultReader_releaseLock, 0, 0),
+ JS_FS_END};
+
+static const JSPropertySpec ReadableStreamDefaultReader_properties[] = {
+ JS_PSG("closed", ReadableStreamDefaultReader_closed, 0), JS_PS_END};
+
+const JSClass ReadableStreamReader::class_ = {"ReadableStreamReader"};
+
+JS_STREAMS_CLASS_SPEC(ReadableStreamDefaultReader, 1, SlotCount,
+ js::ClassSpec::DontDefineConstructor, 0,
+ JS_NULL_CLASS_OPS);