Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/streams/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  ReadableStreamDefaultReader.cpp   Sprache: 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/ReadableStreamDefaultReader.h"

#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/ReadableStream.h"
#include "mozilla/dom/RootedDictionary.h"
#include "js/PropertyAndElement.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "jsapi.h"
#include "mozilla/dom/ReadableStreamDefaultReaderBinding.h"
#include "mozilla/dom/UnderlyingSourceBinding.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"

namespace mozilla::dom {

using namespace streams_abstract;

NS_IMPL_CYCLE_COLLECTION(ReadableStreamGenericReader, mClosedPromise, mStream,
                         mGlobal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadableStreamGenericReader)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadableStreamGenericReader)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ReadableStreamGenericReader)
NS_IMPL_CYCLE_COLLECTION_TRACE_END

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamGenericReader)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_INHERITED(ReadableStreamDefaultReader,
                                                ReadableStreamGenericReader,
                                                mReadRequests)
NS_IMPL_ADDREF_INHERITED(ReadableStreamDefaultReader,
                         ReadableStreamGenericReader)
NS_IMPL_RELEASE_INHERITED(ReadableStreamDefaultReader,
                          ReadableStreamGenericReader)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamDefaultReader)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END_INHERITING(ReadableStreamGenericReader)

ReadableStreamDefaultReader::ReadableStreamDefaultReader(nsISupports* aGlobal)
    : ReadableStreamGenericReader(do_QueryInterface(aGlobal)) {}

ReadableStreamDefaultReader::~ReadableStreamDefaultReader() {
  mReadRequests.clear();
}

JSObject* ReadableStreamDefaultReader::WrapObject(
    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
  return ReadableStreamDefaultReader_Binding::Wrap(aCx, this, aGivenProto);
}

namespace streams_abstract {
// https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize
bool ReadableStreamReaderGenericInitialize(ReadableStreamGenericReader* aReader,
                                           ReadableStream* aStream) {
  // Step 1.
  aReader->SetStream(aStream);

  // Step 2.
  aStream->SetReader(aReader);

  aReader->SetClosedPromise(
      Promise::CreateInfallible(aReader->GetParentObject()));

  switch (aStream->State()) {
      // Step 3.
    case ReadableStream::ReaderState::Readable:
      // Step 3.1
      // Promise created above.
      return true;
    // Step 4.
    case ReadableStream::ReaderState::Closed:
      // Step 4.1.
      aReader->ClosedPromise()->MaybeResolve(JS::UndefinedHandleValue);

      return true;
    // Step 5.
    case ReadableStream::ReaderState::Errored: {
      // Step 5.1 Implicit
      // Step 5.2
      JS::RootingContext* rcx = RootingCx();
      JS::Rooted<JS::Value> rootedError(rcx, aStream->StoredError());
      aReader->ClosedPromise()->MaybeReject(rootedError);

      // Step 5.3
      aReader->ClosedPromise()->SetSettledPromiseIsHandled();
      return true;
    }
    default:
      MOZ_ASSERT_UNREACHABLE("Unknown ReaderState");
      return false;
  }
}
}  // namespace streams_abstract

// https://streams.spec.whatwg.org/#default-reader-constructor &&
// https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
/* static */
already_AddRefed<ReadableStreamDefaultReader>
ReadableStreamDefaultReader::Constructor(const GlobalObject& aGlobal,
                                         ReadableStream& aStream,
                                         ErrorResult& aRv) {
  RefPtr<ReadableStreamDefaultReader> reader =
      new ReadableStreamDefaultReader(aGlobal.GetAsSupports());

  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
  // Step 1.
  if (aStream.Locked()) {
    aRv.ThrowTypeError(
        "Cannot create a new reader for a readable stream already locked by "
        "another reader.");
    return nullptr;
  }

  // Step 2.
  RefPtr<ReadableStream> streamPtr = &aStream;
  if (!ReadableStreamReaderGenericInitialize(reader, streamPtr)) {
    return nullptr;
  }

  // Step 3.
  reader->mReadRequests.clear();

  return reader.forget();
}

void Read_ReadRequest::ChunkSteps(JSContext* aCx, JS::Handle<JS::Value> aChunk,
                                  ErrorResult& aRv) {
  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
  // chunk steps, given chunk:
  //  Step 1. Resolve promise with «[ "value" → chunk, "done" → false ]».

  // Value may need to be wrapped if stream and reader are in different
  // compartments.
  JS::Rooted<JS::Value> chunk(aCx, aChunk);
  if (!JS_WrapValue(aCx, &chunk)) {
    aRv.StealExceptionFromJSContext(aCx);
    return;
  }

  RootedDictionary<ReadableStreamReadResult> result(aCx);
  result.mValue = chunk;
  result.mDone.Construct(false);

  // Ensure that the object is created with the current global.
  JS::Rooted<JS::Value> value(aCx);
  if (!ToJSValue(aCx, std::move(result), &value)) {
    aRv.StealExceptionFromJSContext(aCx);
    return;
  }

  mPromise->MaybeResolve(value);
}

void Read_ReadRequest::CloseSteps(JSContext* aCx, ErrorResult& aRv) {
  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
  // close steps:
  //  Step 1. Resolve promise with «[ "value" → undefined, "done" → true ]».
  RootedDictionary<ReadableStreamReadResult> result(aCx);
  result.mValue.setUndefined();
  result.mDone.Construct(true);

  JS::Rooted<JS::Value> value(aCx);
  if (!ToJSValue(aCx, std::move(result), &value)) {
    aRv.StealExceptionFromJSContext(aCx);
    return;
  }

  mPromise->MaybeResolve(value);
}

void Read_ReadRequest::ErrorSteps(JSContext* aCx, JS::Handle<JS::Value> e,
                                  ErrorResult& aRv) {
  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
  // error steps:
  //  Step 1. Reject promise with e.
  mPromise->MaybeReject(e);
}

NS_IMPL_CYCLE_COLLECTION(ReadRequest)
NS_IMPL_CYCLE_COLLECTION_INHERITED(Read_ReadRequest, ReadRequest, mPromise)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadRequest)

NS_IMPL_ADDREF_INHERITED(Read_ReadRequest, ReadRequest)
NS_IMPL_RELEASE_INHERITED(Read_ReadRequest, ReadRequest)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadRequest)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Read_ReadRequest)
NS_INTERFACE_MAP_END_INHERITING(ReadRequest)

namespace streams_abstract {
// https://streams.spec.whatwg.org/#readable-stream-default-reader-read
void ReadableStreamDefaultReaderRead(JSContext* aCx,
                                     ReadableStreamGenericReader* aReader,
                                     ReadRequest* aRequest, ErrorResult& aRv) {
  // Step 1.
  ReadableStream* stream = aReader->GetStream();

  // Step 2.
  MOZ_ASSERT(stream);

  // Step 3.
  stream->SetDisturbed(true);

  switch (stream->State()) {
    // Step 4.
    case ReadableStream::ReaderState::Closed: {
      aRequest->CloseSteps(aCx, aRv);
      return;
    }

    case ReadableStream::ReaderState::Errored: {
      JS::Rooted<JS::Value> storedError(aCx, stream->StoredError());
      aRequest->ErrorSteps(aCx, storedError, aRv);
      return;
    }

    case ReadableStream::ReaderState::Readable: {
      RefPtr<ReadableStreamController> controller(stream->Controller());
      MOZ_ASSERT(controller);
      controller->PullSteps(aCx, aRequest, aRv);
      return;
    }
  }
}
}  // namespace streams_abstract

// Return a raw pointer here to avoid refcounting, but make sure it's safe
// (the object should be kept alive by the callee).
// https://streams.spec.whatwg.org/#default-reader-read
already_AddRefed<Promise> ReadableStreamDefaultReader::Read(ErrorResult& aRv) {
  // Step 1.
  if (!mStream) {
    aRv.ThrowTypeError("Reading is not possible after calling releaseLock.");
    return nullptr;
  }

  // Step 2.
  RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());

  // Step 3.
  RefPtr<ReadRequest> request = new Read_ReadRequest(promise);

  // Step 4.
  AutoEntryScript aes(mGlobal, "ReadableStreamDefaultReader::Read");
  JSContext* cx = aes.cx();

  ReadableStreamDefaultReaderRead(cx, this, request, aRv);
  if (aRv.Failed()) {
    return nullptr;
  }

  // Step 5.
  return promise.forget();
}

namespace streams_abstract {

// https://streams.spec.whatwg.org/#readable-stream-reader-generic-release
void ReadableStreamReaderGenericRelease(ReadableStreamGenericReader* aReader,
                                        ErrorResult& aRv) {
  // Step 1. Let stream be reader.[[stream]].
  RefPtr<ReadableStream> stream = aReader->GetStream();

  // Step 2. Assert: stream is not undefined.
  MOZ_ASSERT(stream);

  // Step 3. Assert: stream.[[reader]] is reader.
  MOZ_ASSERT(stream->GetReader() == aReader);

  // Step 4. If stream.[[state]] is "readable", reject reader.[[closedPromise]]
  // with a TypeError exception.
  if (stream->State() == ReadableStream::ReaderState::Readable) {
    aReader->ClosedPromise()->MaybeRejectWithTypeError(
        "Releasing lock on readable stream");
  } else {
    // Step 5. Otherwise, set reader.[[closedPromise]] to a promise rejected
    // with a TypeError exception.
    RefPtr<Promise> promise = Promise::CreateRejectedWithTypeError(
        aReader->GetParentObject(), "Lock Released"_ns, aRv);
    aReader->SetClosedPromise(promise.forget());
  }

  // Step 6. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
  aReader->ClosedPromise()->SetSettledPromiseIsHandled();

  // Step 7. Perform ! stream.[[controller]].[[ReleaseSteps]]().
  stream->Controller()->ReleaseSteps();

  // Step 8. Set stream.[[reader]] to undefined.
  stream->SetReader(nullptr);

  // Step 9. Set reader.[[stream]] to undefined.
  aReader->SetStream(nullptr);
}

// https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreadererrorreadrequests
void ReadableStreamDefaultReaderErrorReadRequests(
    JSContext* aCx, ReadableStreamDefaultReader* aReader,
    JS::Handle<JS::Value> aError, ErrorResult& aRv) {
  // Step 1. Let readRequests be reader.[[readRequests]].
  LinkedList<RefPtr<ReadRequest>> readRequests =
      std::move(aReader->ReadRequests());

  // Step 2. Set reader.[[readRequests]] to a new empty list.
  // Note: The std::move already cleared this anyway.
  aReader->ReadRequests().clear();

  // Step 3. For each readRequest of readRequests,
  while (RefPtr<ReadRequest> readRequest = readRequests.popFirst()) {
    // Step 3.1. Perform readRequest’s error steps, given e.
    readRequest->ErrorSteps(aCx, aError, aRv);
    if (aRv.Failed()) {
      return;
    }
  }
}

// https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreaderrelease
void ReadableStreamDefaultReaderRelease(JSContext* aCx,
                                        ReadableStreamDefaultReader* aReader,
                                        ErrorResult& aRv) {
  // Step 1. Perform ! ReadableStreamReaderGenericRelease(reader).
  ReadableStreamReaderGenericRelease(aReader, aRv);
  if (aRv.Failed()) {
    return;
  }

  // Step 2. Let e be a new TypeError exception.
  ErrorResult rv;
  rv.ThrowTypeError("Releasing lock");
  JS::Rooted<JS::Value> error(aCx);
  MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &error));

  // Step 3. Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).
  ReadableStreamDefaultReaderErrorReadRequests(aCx, aReader, error, aRv);
}

}  // namespace streams_abstract

// https://streams.spec.whatwg.org/#default-reader-release-lock
void ReadableStreamDefaultReader::ReleaseLock(ErrorResult& aRv) {
  // Step 1. If this.[[stream]] is undefined, return.
  if (!mStream) {
    return;
  }

  AutoJSAPI jsapi;
  if (!jsapi.Init(mGlobal)) {
    return aRv.ThrowUnknownError("Internal error");
  }
  JSContext* cx = jsapi.cx();

  // Step 2. Perform ! ReadableStreamDefaultReaderRelease(this).
  RefPtr<ReadableStreamDefaultReader> thisRefPtr = this;
  ReadableStreamDefaultReaderRelease(cx, thisRefPtr, aRv);
}

// https://streams.spec.whatwg.org/#generic-reader-closed
already_AddRefed<Promise> ReadableStreamGenericReader::Closed() const {
  // Step 1.
  return do_AddRef(mClosedPromise);
}

// https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel
MOZ_CAN_RUN_SCRIPT
static already_AddRefed<Promise> ReadableStreamGenericReaderCancel(
    JSContext* aCx, ReadableStreamGenericReader* aReader,
    JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
  // Step 1 (Strong ref for below call).
  RefPtr<ReadableStream> stream = aReader->GetStream();

  // Step 2.
  MOZ_ASSERT(stream);

  // Step 3.
  return ReadableStreamCancel(aCx, stream, aReason, aRv);
}

already_AddRefed<Promise> ReadableStreamGenericReader::Cancel(
    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("Canceling is not possible after calling releaseLock.");
    return nullptr;
  }

  // Step 2. Return ! ReadableStreamReaderGenericCancel(this, reason).
  return ReadableStreamGenericReaderCancel(aCx, this, aReason, aRv);
}

namespace streams_abstract {
// https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
void SetUpReadableStreamDefaultReader(ReadableStreamDefaultReader* aReader,
                                      ReadableStream* aStream,
                                      ErrorResult& aRv) {
  // Step 1.
  if (IsReadableStreamLocked(aStream)) {
    return aRv.ThrowTypeError(
        "Cannot get a new reader for a readable stream already locked by "
        "another reader.");
  }

  // Step 2.
  if (!ReadableStreamReaderGenericInitialize(aReader, aStream)) {
    return;
  }

  // Step 3.
  aReader->ReadRequests().clear();
}
}  // namespace streams_abstract

// https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-a-chunk
// To read a chunk from a ReadableStreamDefaultReader reader, given a read
// request readRequest, perform ! ReadableStreamDefaultReaderRead(reader,
// readRequest).
void ReadableStreamDefaultReader::ReadChunk(JSContext* aCx,
                                            ReadRequest& aRequest,
                                            ErrorResult& aRv) {
  ReadableStreamDefaultReaderRead(aCx, this, &aRequest, aRv);
}

}  // namespace mozilla::dom

98%


¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.