mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Backed out changeset 2693a863dabd (bug 1272697)
This commit is contained in:
parent
5dd8373329
commit
08625237bc
@ -1,522 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
* JSAPI functions and callbacks related to WHATWG Stream objects.
|
||||
*
|
||||
* Much of the API here mirrors the JS API of ReadableStream and associated
|
||||
* classes, e.g. ReadableStreamDefaultReader, ReadableStreamBYOBReader,
|
||||
* ReadableStreamDefaultController, ReadableByteStreamController, and
|
||||
* ReadableStreamBYOBRequest.
|
||||
*
|
||||
* There are some crucial differences, though: Functionality that's exposed
|
||||
* as methods/accessors on controllers in JS is exposed as functions taking
|
||||
* ReadableStream instances instead. This is because an analysis of how
|
||||
* the API would be used showed that all functions that'd take controllers
|
||||
* would do so by first getting the controller from the stream instance it's
|
||||
* associated with and then call the function taking it. I.e., it would purely
|
||||
* add boilerplate without any gains in ease of use of the API.
|
||||
*
|
||||
* It would probably still make sense to factor the API the same as the JS API
|
||||
* if we had to keep any API stability guarantees: the JS API won't change, so
|
||||
* we could be sure that the C++ API could stay the same, too. Given that we
|
||||
* don't guarantee API stability, this concern isn't too pressing.
|
||||
*
|
||||
* Some functions exposed here deal with ReadableStream instances that have an
|
||||
* embedding-provided underlying source. These instances are largely similar
|
||||
* to byte streams as created using |new ReadableStream({type: "bytes"})|:
|
||||
* They enable users to acquire ReadableStreamBYOBReaders and only vend chunks
|
||||
* that're typed array instances.
|
||||
*
|
||||
* When creating an "external readable stream" using
|
||||
* JS::NewReadableExternalSourceStreamObject, an underlying source and a set
|
||||
* of flags can be passed to be stored on the stream. The underlying source is
|
||||
* treated as an opaque void* pointer by the JS engine: it's purely meant as
|
||||
* a reference to be used by the embedding to identify whatever actual source
|
||||
* it uses to supply data for the stream. Similarly, the flags aren't
|
||||
* interpreted by the JS engine, but are passed to some of the callbacks below
|
||||
* and can be retrieved using JS::ReadableStreamGetEmbeddingFlags.
|
||||
*
|
||||
* External readable streams are optimized to allow the embedding to interact
|
||||
* with them with a minimum of overhead: chunks aren't enqueued as individual
|
||||
* typed array instances; instead, the embedding only updates the amount of
|
||||
* data available using ReadableStreamUpdateDataAvailableFromSource.
|
||||
* When content requests data by reading from a reader,
|
||||
* WriteIntoReadRequestBufferCallback is invoked, asking the embedding to
|
||||
* write data directly into the buffer we're about to hand to content.
|
||||
*
|
||||
* Additionally, ReadableStreamGetExternalUnderlyingSource can be used to
|
||||
* get the void* pointer to the underlying source. This is equivalent to
|
||||
* acquiring a reader for the stream in that it locks the stream until it
|
||||
* is released again using JS::ReadableStreamReleaseExternalUnderlyingSource.
|
||||
*
|
||||
* Embeddings are expected to detect situations where an API exposed to JS
|
||||
* takes a ReadableStream to read from that has an external underlying source.
|
||||
* In those situations, it might be preferable to directly perform data
|
||||
* transfers from the stream's underlying source to whatever sink the
|
||||
* embedding uses, assuming that such direct transfers can be performed
|
||||
* more efficiently.
|
||||
*
|
||||
* An example of such an optimized operation might be a ServiceWorker piping a
|
||||
* fetch Response body to a TextDecoder: instead of writing chunks of data
|
||||
* into JS typed array buffers only to immediately read from them again, the
|
||||
* embedding can presumably directly feed the incoming data to the
|
||||
* TextDecoder's underlying implementation.
|
||||
*/
|
||||
|
||||
#ifndef js_Stream_h
|
||||
#define js_Stream_h
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
/**
|
||||
* Invoked whenever a reader desires more data from a ReadableStream's
|
||||
* embedding-provided underlying source.
|
||||
*
|
||||
* The given |desiredSize| is the absolute size, not a delta from the previous
|
||||
* desired size.
|
||||
*/
|
||||
typedef void
|
||||
(* RequestReadableStreamDataCallback)(JSContext* cx, HandleObject stream,
|
||||
void* underlyingSource, uint8_t flags, size_t desiredSize);
|
||||
|
||||
/**
|
||||
* Invoked to cause the embedding to fill the given |buffer| with data from
|
||||
* the given embedding-provided underlying source.
|
||||
*
|
||||
* This can only happen after the embedding has updated the amount of data
|
||||
* available using JS::ReadableStreamUpdateDataAvailableFromSource. If at
|
||||
* least one read request is pending when
|
||||
* JS::ReadableStreamUpdateDataAvailableFromSource is called,
|
||||
* the WriteIntoReadRequestBufferCallback is invoked immediately from under
|
||||
* the call to JS::WriteIntoReadRequestBufferCallback. If not, it is invoked
|
||||
* if and when a new read request is made.
|
||||
*
|
||||
* Note: This callback *must not cause GC*, because that could potentially
|
||||
* invalidate the |buffer| pointer.
|
||||
*/
|
||||
typedef void
|
||||
(* WriteIntoReadRequestBufferCallback)(JSContext* cx, HandleObject stream,
|
||||
void* underlyingSource, uint8_t flags, void* buffer,
|
||||
size_t length, size_t* bytesWritten);
|
||||
|
||||
/**
|
||||
* Invoked in reaction to the ReadableStream being canceled to allow the
|
||||
* embedding to free the underlying source.
|
||||
*
|
||||
* This is equivalent to calling |cancel| on non-external underlying sources
|
||||
* provided to the ReadableStream constructor in JavaScript.
|
||||
*
|
||||
* The given |reason| is the JS::Value that was passed as an argument to
|
||||
* ReadableStream#cancel().
|
||||
*
|
||||
* The returned JS::Value will be used to resolve the Promise returned by
|
||||
* ReadableStream#cancel().
|
||||
*/
|
||||
typedef Value
|
||||
(* CancelReadableStreamCallback)(JSContext* cx, HandleObject stream,
|
||||
void* underlyingSource, uint8_t flags, HandleValue reason);
|
||||
|
||||
/**
|
||||
* Invoked in reaction to a ReadableStream with an embedding-provided
|
||||
* underlying source being closed.
|
||||
*/
|
||||
typedef void
|
||||
(* ReadableStreamClosedCallback)(JSContext* cx, HandleObject stream, void* underlyingSource,
|
||||
uint8_t flags);
|
||||
|
||||
/**
|
||||
* Invoked in reaction to a ReadableStream with an embedding-provided
|
||||
* underlying source being errored with the
|
||||
* given reason.
|
||||
*/
|
||||
typedef void
|
||||
(* ReadableStreamErroredCallback)(JSContext* cx, HandleObject stream, void* underlyingSource,
|
||||
uint8_t flags, HandleValue reason);
|
||||
|
||||
/**
|
||||
* Invoked in reaction to a ReadableStream with an embedding-provided
|
||||
* underlying source being finalized. Only the underlying source is passed
|
||||
* as an argument, while the ReadableStream itself is not to prevent the
|
||||
* embedding from operating on a JSObject that might not be in a valid state
|
||||
* anymore.
|
||||
*
|
||||
* Note: the ReadableStream might be finalized on a background thread. That
|
||||
* means this callback might be invoked from an arbitrary thread, which the
|
||||
* embedding must be able to handle.
|
||||
*/
|
||||
typedef void
|
||||
(* ReadableStreamFinalizeCallback)(void* underlyingSource, uint8_t flags);
|
||||
|
||||
/**
|
||||
* Sets runtime-wide callbacks to use for interacting with embedding-provided
|
||||
* hooks for operating on ReadableStream instances.
|
||||
*
|
||||
* See the documentation for the individual callback types for details.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetReadableStreamCallbacks(JSContext* cx,
|
||||
RequestReadableStreamDataCallback dataRequestCallback,
|
||||
WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback,
|
||||
CancelReadableStreamCallback cancelCallback,
|
||||
ReadableStreamClosedCallback closedCallback,
|
||||
ReadableStreamErroredCallback erroredCallback,
|
||||
ReadableStreamFinalizeCallback finalizeCallback);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
HasReadableStreamCallbacks(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Returns a new instance of the ReadableStream builtin class in the current
|
||||
* compartment, configured as a default stream.
|
||||
* If a |proto| is passed, that gets set as the instance's [[Prototype]]
|
||||
* instead of the original value of |ReadableStream.prototype|.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
NewReadableDefaultStreamObject(JSContext* cx, HandleObject underlyingSource = nullptr,
|
||||
HandleFunction size = nullptr, double highWaterMark = 1,
|
||||
HandleObject proto = nullptr);
|
||||
|
||||
/**
|
||||
* Returns a new instance of the ReadableStream builtin class in the current
|
||||
* compartment, configured as a byte stream.
|
||||
* If a |proto| is passed, that gets set as the instance's [[Prototype]]
|
||||
* instead of the original value of |ReadableStream.prototype|.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
NewReadableByteStreamObject(JSContext* cx, HandleObject underlyingSource = nullptr,
|
||||
double highWaterMark = 0, HandleObject proto = nullptr);
|
||||
|
||||
/**
|
||||
* Returns a new instance of the ReadableStream builtin class in the current
|
||||
* compartment, with the right slot layout. If a |proto| is passed, that gets
|
||||
* set as the instance's [[Prototype]] instead of the original value of
|
||||
* |ReadableStream.prototype|.
|
||||
*
|
||||
* The instance is optimized for operating as a byte stream backed by an
|
||||
* embedding-provided underlying source, using the callbacks set via
|
||||
* |JS::SetReadableStreamCallbacks|.
|
||||
*
|
||||
* The given |flags| will be passed to all applicable callbacks and can be
|
||||
* used to disambiguate between different types of stream sources the
|
||||
* embedding might support.
|
||||
*
|
||||
* Note: the embedding is responsible for ensuring that the pointer to the
|
||||
* underlying source stays valid as long as the stream can be read from.
|
||||
* The underlying source can be freed if the tree is canceled or errored.
|
||||
* It can also be freed if the stream is destroyed. The embedding is notified
|
||||
* of that using ReadableStreamFinalizeCallback.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
NewReadableExternalSourceStreamObject(JSContext* cx, void* underlyingSource,
|
||||
uint8_t flags = 0, HandleObject proto = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the flags that were passed to NewReadableExternalSourceStreamObject
|
||||
* when creating the given stream.
|
||||
*
|
||||
* Asserts that the given stream has an embedding-provided underlying source.
|
||||
*/
|
||||
extern JS_PUBLIC_API(uint8_t)
|
||||
ReadableStreamGetEmbeddingFlags(const JSObject* stream);
|
||||
|
||||
/**
|
||||
* Returns the embedding-provided underlying source of the given |stream|.
|
||||
*
|
||||
* Can be used to optimize operations if both the underlying source and the
|
||||
* intended sink are embedding-provided. In that case it might be
|
||||
* preferrable to pipe data directly from source to sink without interacting
|
||||
* with the stream at all.
|
||||
*
|
||||
* Locks the stream until ReadableStreamReleaseExternalUnderlyingSource is
|
||||
* called.
|
||||
*
|
||||
* Throws an exception if the stream is locked, i.e. if a reader has been
|
||||
* acquired for the stream, or if ReadableStreamGetExternalUnderlyingSource
|
||||
* has been used previously without releasing the external source again.
|
||||
*
|
||||
* Throws an exception if the stream isn't readable, i.e if it is errored or
|
||||
* closed. This is different from ReadableStreamGetReader because we don't
|
||||
* have a Promise to resolve/reject, which a reader provides.
|
||||
*
|
||||
* Asserts that the stream has an embedding-provided underlying source.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamGetExternalUnderlyingSource(JSContext* cx, HandleObject stream, void** source);
|
||||
|
||||
/**
|
||||
* Releases the embedding-provided underlying source of the given |stream|,
|
||||
* returning the stream into an unlocked state.
|
||||
*
|
||||
* Asserts that the stream was locked through
|
||||
* ReadableStreamGetExternalUnderlyingSource.
|
||||
*
|
||||
* Asserts that the stream has an embedding-provided underlying source.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
ReadableStreamReleaseExternalUnderlyingSource(JSObject* stream);
|
||||
|
||||
/**
|
||||
* Update the amount of data available at the underlying source of the given
|
||||
* |stream|.
|
||||
*
|
||||
* Can only be used for streams with an embedding-provided underlying source.
|
||||
* The JS engine will use the given value to satisfy read requests for the
|
||||
* stream by invoking the JS::WriteIntoReadRequestBuffer callback.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamUpdateDataAvailableFromSource(JSContext* cx, HandleObject stream,
|
||||
uint32_t availableData);
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an unwrapped ReadableStream object,
|
||||
* false otherwise.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsReadableStream(const JSObject* obj);
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an unwrapped
|
||||
* ReadableStreamDefaultReader or ReadableStreamBYOBReader object,
|
||||
* false otherwise.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsReadableStreamReader(const JSObject* obj);
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an unwrapped
|
||||
* ReadableStreamDefaultReader object, false otherwise.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsReadableStreamDefaultReader(const JSObject* obj);
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an unwrapped
|
||||
* ReadableStreamBYOBReader object, false otherwise.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsReadableStreamBYOBReader(const JSObject* obj);
|
||||
|
||||
enum class ReadableStreamMode {
|
||||
Default,
|
||||
Byte,
|
||||
ExternalSource
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the stream's ReadableStreamMode. If the mode is |Byte| or
|
||||
* |ExternalSource|, it's possible to acquire a BYOB reader for more optimized
|
||||
* operations.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(ReadableStreamMode)
|
||||
ReadableStreamGetMode(const JSObject* stream);
|
||||
|
||||
enum class ReadableStreamReaderMode {
|
||||
Default,
|
||||
BYOB
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the given ReadableStream is readable, false if not.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamIsReadable(const JSObject* stream);
|
||||
|
||||
/**
|
||||
* Returns true if the given ReadableStream is locked, false if not.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamIsLocked(const JSObject* stream);
|
||||
|
||||
/**
|
||||
* Returns true if the given ReadableStream is disturbed, false if not.
|
||||
*
|
||||
* Asserts that |stream| is an ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamIsDisturbed(const JSObject* stream);
|
||||
|
||||
/**
|
||||
* Cancels the given ReadableStream with the given reason and returns a
|
||||
* Promise resolved according to the result.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
ReadableStreamCancel(JSContext* cx, HandleObject stream, HandleValue reason);
|
||||
|
||||
/**
|
||||
* Creates a reader of the type specified by the mode option and locks the
|
||||
* stream to the new reader.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
ReadableStreamGetReader(JSContext* cx, HandleObject stream, ReadableStreamReaderMode mode);
|
||||
|
||||
/**
|
||||
* Tees the given ReadableStream and stores the two resulting streams in
|
||||
* outparams. Returns false if the operation fails, e.g. because the stream is
|
||||
* locked.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamTee(JSContext* cx, HandleObject stream,
|
||||
MutableHandleObject branch1Stream, MutableHandleObject branch2Stream);
|
||||
|
||||
/**
|
||||
* Retrieves the desired combined size of additional chunks to fill the given
|
||||
* ReadableStream's queue. Stores the result in |value| and sets |hasValue| to
|
||||
* true on success, returns false on failure.
|
||||
*
|
||||
* If the stream is errored, the call will succeed but no value will be stored
|
||||
* in |value| and |hasValue| will be set to false.
|
||||
*
|
||||
* Note: This is semantically equivalent to the |desiredSize| getter on
|
||||
* the stream controller's prototype in JS. We expose it with the stream
|
||||
* itself as a target for simplicity.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
ReadableStreamGetDesiredSize(JSObject* stream, bool* hasValue, double* value);
|
||||
|
||||
/**
|
||||
* Closes the given ReadableStream.
|
||||
*
|
||||
* Throws a TypeError and returns false if the closing operation fails.
|
||||
*
|
||||
* Note: This is semantically equivalent to the |close| method on
|
||||
* the stream controller's prototype in JS. We expose it with the stream
|
||||
* itself as a target for simplicity.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamClose(JSContext* cx, HandleObject stream);
|
||||
|
||||
/**
|
||||
* Returns true if the given ReadableStream reader is locked, false otherwise.
|
||||
*
|
||||
* Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or
|
||||
* ReadableStreamBYOBReader instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamReaderIsClosed(const JSObject* reader);
|
||||
|
||||
/**
|
||||
* Enqueues the given chunk in the given ReadableStream.
|
||||
*
|
||||
* Throws a TypeError and returns false if the enqueing operation fails.
|
||||
*
|
||||
* Note: This is semantically equivalent to the |enqueue| method on
|
||||
* the stream controller's prototype in JS. We expose it with the stream
|
||||
* itself as a target for simplicity.
|
||||
*
|
||||
* If the ReadableStream has an underlying byte source, the given chunk must
|
||||
* be a typed array or a DataView. Consider using
|
||||
* ReadableByteStreamEnqueueBuffer.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamEnqueue(JSContext* cx, HandleObject stream, HandleValue chunk);
|
||||
|
||||
/**
|
||||
* Enqueues the given buffer as a chunk in the given ReadableStream.
|
||||
*
|
||||
* Throws a TypeError and returns false if the enqueing operation fails.
|
||||
*
|
||||
* Note: This is semantically equivalent to the |enqueue| method on
|
||||
* the stream controller's prototype in JS. We expose it with the stream
|
||||
* itself as a target for simplicity. Additionally, the JS version only
|
||||
* takes typed arrays and ArrayBufferView instances as arguments, whereas
|
||||
* this takes an ArrayBuffer, obviating the need to wrap it into a typed
|
||||
* array.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance and |buffer|
|
||||
* an unwrapped ArrayBuffer instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableByteStreamEnqueueBuffer(JSContext* cx, HandleObject stream, HandleObject buffer);
|
||||
|
||||
/**
|
||||
* Errors the given ReadableStream, causing all future interactions to fail
|
||||
* with the given error value.
|
||||
*
|
||||
* Throws a TypeError and returns false if the erroring operation fails.
|
||||
*
|
||||
* Note: This is semantically equivalent to the |error| method on
|
||||
* the stream controller's prototype in JS. We expose it with the stream
|
||||
* itself as a target for simplicity.
|
||||
*
|
||||
* Asserts that |stream| is an unwrapped ReadableStream instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamError(JSContext* cx, HandleObject stream, HandleValue error);
|
||||
|
||||
/**
|
||||
* Cancels the given ReadableStream reader's associated stream.
|
||||
*
|
||||
* Throws a TypeError and returns false if the given reader isn't active.
|
||||
*
|
||||
* Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or
|
||||
* ReadableStreamBYOBReader instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamReaderCancel(JSContext* cx, HandleObject reader, HandleValue reason);
|
||||
|
||||
/**
|
||||
* Cancels the given ReadableStream reader's associated stream.
|
||||
*
|
||||
* Throws a TypeError and returns false if the given reader has pending
|
||||
* read or readInto (for default or byob readers, respectively) requests.
|
||||
*
|
||||
* Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or
|
||||
* ReadableStreamBYOBReader instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
ReadableStreamReaderReleaseLock(JSContext* cx, HandleObject reader);
|
||||
|
||||
/**
|
||||
* Requests a read from the reader's associated ReadableStream and returns the
|
||||
* resulting PromiseObject.
|
||||
*
|
||||
* Returns a Promise that's resolved with the read result once available or
|
||||
* rejected immediately if the stream is errored or the operation failed.
|
||||
*
|
||||
* Asserts that |reader| is an unwrapped ReadableStreamDefaultReader instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
ReadableStreamDefaultReaderRead(JSContext* cx, HandleObject reader);
|
||||
|
||||
/**
|
||||
* Requests a read from the reader's associated ReadableStream into the given
|
||||
* ArrayBufferView and returns the resulting PromiseObject.
|
||||
*
|
||||
* Returns a Promise that's resolved with the read result once available or
|
||||
* rejected immediately if the stream is errored or the operation failed.
|
||||
*
|
||||
* Asserts that |reader| is an unwrapped ReadableStreamDefaultReader and
|
||||
* |view| an unwrapped typed array or DataView instance.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
ReadableStreamBYOBReaderRead(JSContext* cx, HandleObject reader, HandleObject view);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_Realm_h
|
File diff suppressed because it is too large
Load Diff
@ -7,10 +7,8 @@
|
||||
#ifndef builtin_Stream_h
|
||||
#define builtin_Stream_h
|
||||
|
||||
#include "builtin/Promise.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoSetNewObjectMetadata;
|
||||
@ -19,50 +17,14 @@ class ReadableStream : public NativeObject
|
||||
{
|
||||
public:
|
||||
static ReadableStream* createDefaultStream(JSContext* cx, HandleValue underlyingSource,
|
||||
HandleValue size, HandleValue highWaterMark,
|
||||
HandleObject proto = nullptr);
|
||||
HandleValue size, HandleValue highWaterMark);
|
||||
static ReadableStream* createByteStream(JSContext* cx, HandleValue underlyingSource,
|
||||
HandleValue highWaterMark,
|
||||
HandleObject proto = nullptr);
|
||||
static ReadableStream* createExternalSourceStream(JSContext* cx, void* underlyingSource,
|
||||
uint8_t flags, HandleObject proto = nullptr);
|
||||
HandleValue highWaterMark);
|
||||
|
||||
bool readable() const;
|
||||
bool closed() const;
|
||||
bool errored() const;
|
||||
bool disturbed() const;
|
||||
|
||||
bool locked() const;
|
||||
|
||||
void desiredSize(bool* hasSize, double* size) const;
|
||||
|
||||
JS::ReadableStreamMode mode() const;
|
||||
|
||||
static MOZ_MUST_USE bool close(JSContext* cx, Handle<ReadableStream*> stream);
|
||||
static MOZ_MUST_USE JSObject* cancel(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
HandleValue reason);
|
||||
static MOZ_MUST_USE bool error(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
HandleValue error);
|
||||
|
||||
static MOZ_MUST_USE NativeObject* getReader(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
JS::ReadableStreamReaderMode mode);
|
||||
|
||||
static MOZ_MUST_USE bool tee(JSContext* cx,
|
||||
Handle<ReadableStream*> stream, bool cloneForBranch2,
|
||||
MutableHandle<ReadableStream*> branch1Stream,
|
||||
MutableHandle<ReadableStream*> branch2Stream);
|
||||
|
||||
static MOZ_MUST_USE bool enqueue(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
HandleValue chunk);
|
||||
static MOZ_MUST_USE bool enqueueBuffer(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
Handle<ArrayBufferObject*> chunk);
|
||||
static MOZ_MUST_USE bool getExternalSource(JSContext* cx, Handle<ReadableStream*> stream,
|
||||
void** source);
|
||||
void releaseExternalSource();
|
||||
uint8_t embeddingFlags() const;
|
||||
static MOZ_MUST_USE bool updateDataAvailableFromSource(JSContext* cx,
|
||||
Handle<ReadableStream*> stream,
|
||||
uint32_t availableData);
|
||||
inline bool readable() const;
|
||||
inline bool closed() const;
|
||||
inline bool errored() const;
|
||||
inline bool disturbed() const;
|
||||
|
||||
enum State {
|
||||
Readable = 1 << 0,
|
||||
@ -72,7 +34,7 @@ class ReadableStream : public NativeObject
|
||||
};
|
||||
|
||||
private:
|
||||
static MOZ_MUST_USE ReadableStream* createStream(JSContext* cx, HandleObject proto = nullptr);
|
||||
static ReadableStream* createStream(JSContext* cx);
|
||||
|
||||
public:
|
||||
static bool constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
@ -85,8 +47,6 @@ class ReadableStream : public NativeObject
|
||||
class ReadableStreamDefaultReader : public NativeObject
|
||||
{
|
||||
public:
|
||||
static MOZ_MUST_USE JSObject* read(JSContext* cx, Handle<ReadableStreamDefaultReader*> reader);
|
||||
|
||||
static bool constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
static const ClassSpec classSpec_;
|
||||
static const Class class_;
|
||||
@ -97,9 +57,6 @@ class ReadableStreamDefaultReader : public NativeObject
|
||||
class ReadableStreamBYOBReader : public NativeObject
|
||||
{
|
||||
public:
|
||||
static MOZ_MUST_USE JSObject* read(JSContext* cx, Handle<ReadableStreamBYOBReader*> reader,
|
||||
Handle<ArrayBufferViewObject*> view);
|
||||
|
||||
static bool constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
static const ClassSpec classSpec_;
|
||||
static const Class class_;
|
||||
@ -107,13 +64,6 @@ class ReadableStreamBYOBReader : public NativeObject
|
||||
static const Class protoClass_;
|
||||
};
|
||||
|
||||
bool ReadableStreamReaderIsClosed(const JSObject* reader);
|
||||
|
||||
MOZ_MUST_USE bool ReadableStreamReaderCancel(JSContext* cx, HandleObject reader,
|
||||
HandleValue reason);
|
||||
|
||||
MOZ_MUST_USE bool ReadableStreamReaderReleaseLock(JSContext* cx, HandleObject reader);
|
||||
|
||||
class ReadableStreamDefaultController : public NativeObject
|
||||
{
|
||||
public:
|
||||
@ -127,8 +77,6 @@ class ReadableStreamDefaultController : public NativeObject
|
||||
class ReadableByteStreamController : public NativeObject
|
||||
{
|
||||
public:
|
||||
bool hasExternalSource();
|
||||
|
||||
static bool constructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
static const ClassSpec classSpec_;
|
||||
static const Class class_;
|
||||
|
@ -611,19 +611,18 @@ MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_OFFSET, 0, JSEXN_RANGEERR, "view offset does not match requested position.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED, 1, JSEXN_TYPEERR, "'{0}' may only be called on a locked stream.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED, 1, JSEXN_TYPEERR, "The ReadableStream method '{0}' may only be called on a locked stream.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_LOCKED, 0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableByteStreamController.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 0, JSEXN_TYPEERR, "ReadableStream.getReader('byob') requires a ReadableByteStreamController.")
|
||||
MSG_DEF(JSMSG_READABLESTREAM_CONTROLLER_SET, 0, JSEXN_TYPEERR, "The ReadableStream already has a controller defined.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_OWNED, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may only be called on a reader owned by a stream.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_EMPTY, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may not be called on a reader with read requests.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMBYOBREADER_READ_EMPTY_VIEW, 0, JSEXN_TYPEERR, "ReadableStreamBYOBReader.read() was passed an empty TypedArrayBuffer view.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMREADER_RELEASED, 0, JSEXN_TYPEERR, "The ReadableStream reader was released.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_CLOSED, 1, JSEXN_TYPEERR, "'{0}' called on a stream already closing.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_NOT_READABLE, 1, JSEXN_TYPEERR, "'{0}' may only be called on a stream in the 'readable' state.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_CLOSED, 1, JSEXN_TYPEERR, "The ReadableStream controller method '{0}' called on a stream already closing.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_NOT_READABLE, 1, JSEXN_TYPEERR, "The ReadableStream controller method '{0}' may only be called on a stream in the 'readable' state.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNKSIZE,0, JSEXN_RANGEERR, "ReadableByteStreamController requires a positive integer or undefined for 'autoAllocateChunkSize'.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK, 1, JSEXN_TYPEERR, "{0} passed a bad chunk.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK, 0, JSEXN_TYPEERR, "ReadableByteStreamController passed a bad chunk.")
|
||||
MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_CLOSE_PENDING_PULL, 0, JSEXN_TYPEERR, "The ReadableByteStreamController cannot be closed while the buffer is being filled.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_NO_CONTROLLER, 1, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method '{0}' called on a request with no controller.")
|
||||
MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_RESPOND_CLOSED, 0, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method 'respond' called with non-zero number of bytes with a closed controller.")
|
||||
|
@ -125,11 +125,6 @@ if CONFIG['ENABLE_ION']:
|
||||
'testJitRValueAlloc.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_STREAMS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'testReadableStream.cpp',
|
||||
]
|
||||
|
||||
DEFINES['EXPORT_JS_API'] = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "js/RequiredDefines.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#include "js/Stream.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/TrackedOptimizationInfo.h"
|
||||
|
@ -1,678 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*/
|
||||
/* 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 "jsapi.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using namespace JS;
|
||||
|
||||
char test_buffer_data[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
static JSObject*
|
||||
NewDefaultStream(JSContext* cx, HandleObject source = nullptr, HandleFunction size = nullptr,
|
||||
double highWaterMark = 1, HandleObject proto = nullptr)
|
||||
{
|
||||
RootedObject stream(cx, NewReadableDefaultStreamObject(cx, source, size, highWaterMark,
|
||||
proto));
|
||||
MOZ_ASSERT_IF(stream, IsReadableStream(stream));
|
||||
return stream;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
NewByteStream(JSContext* cx, double highWaterMark = 0, HandleObject proto = nullptr)
|
||||
{
|
||||
RootedObject source(cx, JS_NewPlainObject(cx));
|
||||
MOZ_ASSERT(source);
|
||||
|
||||
RootedObject stream(cx, NewReadableByteStreamObject(cx, source, highWaterMark, proto));
|
||||
MOZ_ASSERT_IF(stream, IsReadableStream(stream));
|
||||
return stream;
|
||||
}
|
||||
|
||||
static bool dataRequestCBCalled = false;
|
||||
static void
|
||||
DataRequestCB(JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags,
|
||||
size_t desiredSize)
|
||||
{
|
||||
MOZ_ASSERT(!dataRequestCBCalled, "Invalid test setup");
|
||||
dataRequestCBCalled = true;
|
||||
}
|
||||
|
||||
static bool writeIntoRequestBufferCBCalled = false;
|
||||
static void
|
||||
WriteIntoRequestBufferCB(JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags,
|
||||
void* buffer, size_t length, size_t* bytesWritten)
|
||||
{
|
||||
MOZ_ASSERT(!writeIntoRequestBufferCBCalled, "Invalid test setup");
|
||||
MOZ_ASSERT(length <= sizeof(test_buffer_data));
|
||||
memcpy(buffer, test_buffer_data, length);
|
||||
writeIntoRequestBufferCBCalled = true;
|
||||
*bytesWritten = length;
|
||||
}
|
||||
|
||||
static bool cancelStreamCBCalled = false;
|
||||
static Value cancelStreamReason;
|
||||
static Value
|
||||
CancelStreamCB(JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags,
|
||||
HandleValue reason)
|
||||
{
|
||||
MOZ_ASSERT(!cancelStreamCBCalled, "Invalid test setup");
|
||||
cancelStreamCBCalled = true;
|
||||
cancelStreamReason = reason;
|
||||
return reason;
|
||||
}
|
||||
|
||||
static bool streamClosedCBCalled = false;
|
||||
static Value streamClosedReason;
|
||||
static void
|
||||
StreamClosedCB(JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags)
|
||||
{
|
||||
MOZ_ASSERT(!streamClosedCBCalled, "Invalid test setup");
|
||||
streamClosedCBCalled = true;
|
||||
}
|
||||
|
||||
static bool streamErroredCBCalled = false;
|
||||
static Value streamErroredReason;
|
||||
static void
|
||||
StreamErroredCB(JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags,
|
||||
HandleValue reason)
|
||||
{
|
||||
MOZ_ASSERT(!streamErroredCBCalled, "Invalid test setup");
|
||||
streamErroredCBCalled = true;
|
||||
streamErroredReason = reason;
|
||||
}
|
||||
|
||||
static bool finalizeStreamCBCalled = false;
|
||||
static void* finalizedStreamUnderlyingSource;
|
||||
static void
|
||||
FinalizeStreamCB(void* underlyingSource, uint8_t flags)
|
||||
{
|
||||
MOZ_ASSERT(!finalizeStreamCBCalled, "Invalid test setup");
|
||||
finalizeStreamCBCalled = true;
|
||||
finalizedStreamUnderlyingSource = underlyingSource;
|
||||
}
|
||||
|
||||
static void
|
||||
ResetCallbacks()
|
||||
{
|
||||
dataRequestCBCalled = false;
|
||||
writeIntoRequestBufferCBCalled = false;
|
||||
cancelStreamReason = UndefinedValue();
|
||||
cancelStreamCBCalled = false;
|
||||
streamClosedCBCalled = false;
|
||||
streamErroredCBCalled = false;
|
||||
finalizeStreamCBCalled = false;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetIterResult(JSContext* cx, HandleObject promise, MutableHandleValue value, bool* done)
|
||||
{
|
||||
RootedObject iterResult(cx, &GetPromiseResult(promise).toObject());
|
||||
|
||||
bool found;
|
||||
if (!JS_HasProperty(cx, iterResult, "value", &found))
|
||||
return false;
|
||||
MOZ_ASSERT(found);
|
||||
if (!JS_HasProperty(cx, iterResult, "done", &found))
|
||||
return false;
|
||||
MOZ_ASSERT(found);
|
||||
|
||||
RootedValue doneVal(cx);
|
||||
if (!JS_GetProperty(cx, iterResult, "value", value))
|
||||
return false;
|
||||
if (!JS_GetProperty(cx, iterResult, "done", &doneVal))
|
||||
return false;
|
||||
|
||||
*done = doneVal.toBoolean();
|
||||
MOZ_ASSERT_IF(*done, value.isUndefined());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
GetReadChunk(JSContext* cx, HandleObject readRequest)
|
||||
{
|
||||
MOZ_ASSERT(GetPromiseState(readRequest) == PromiseState::Fulfilled);
|
||||
RootedValue resultVal(cx, GetPromiseResult(readRequest));
|
||||
MOZ_ASSERT(resultVal.isObject());
|
||||
RootedObject result(cx, &resultVal.toObject());
|
||||
RootedValue chunkVal(cx);
|
||||
JS_GetProperty(cx, result, "value", &chunkVal);
|
||||
return &chunkVal.toObject();
|
||||
}
|
||||
|
||||
BEGIN_TEST(testReadableStream_NewReadableStream)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
CHECK(ReadableStreamGetMode(stream) == ReadableStreamMode::Default);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_NewReadableStream)
|
||||
|
||||
BEGIN_TEST(testReadableStream_NewReadableByteStream)
|
||||
{
|
||||
RootedObject stream(cx, NewByteStream(cx));
|
||||
CHECK(stream);
|
||||
CHECK(ReadableStreamGetMode(stream) == ReadableStreamMode::Byte);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_NewReadableByteStream)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamGetReaderDefault)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default));
|
||||
CHECK(reader);
|
||||
CHECK(IsReadableStreamDefaultReader(reader));
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
CHECK(!ReadableStreamReaderIsClosed(reader));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamGetReaderDefault)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamGetReaderBYOB)
|
||||
{
|
||||
RootedObject stream(cx, NewByteStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::BYOB));
|
||||
CHECK(reader);
|
||||
CHECK(IsReadableStreamBYOBReader(reader));
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
CHECK(!ReadableStreamReaderIsClosed(reader));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamGetReaderBYOB)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamTee)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject leftStream(cx);
|
||||
RootedObject rightStream(cx);
|
||||
CHECK(ReadableStreamTee(cx, stream, &leftStream, &rightStream));
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
CHECK(leftStream);
|
||||
CHECK(IsReadableStream(leftStream));
|
||||
CHECK(rightStream);
|
||||
CHECK(IsReadableStream(rightStream));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamTee)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamEnqueue)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject chunk(cx, JS_NewPlainObject(cx));
|
||||
CHECK(chunk);
|
||||
RootedValue chunkVal(cx, ObjectValue(*chunk));
|
||||
CHECK(ReadableStreamEnqueue(cx, stream, chunkVal));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamEnqueue)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableByteStreamEnqueue)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject chunk(cx, JS_NewUint8Array(cx, 42));
|
||||
CHECK(chunk);
|
||||
CHECK(!ReadableByteStreamEnqueueBuffer(cx, stream, chunk));
|
||||
CHECK(JS_IsExceptionPending(cx));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableByteStreamEnqueue)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamDefaultReaderRead)
|
||||
{
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default));
|
||||
CHECK(reader);
|
||||
|
||||
RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
|
||||
CHECK(request);
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
|
||||
RootedObject chunk(cx, JS_NewPlainObject(cx));
|
||||
CHECK(chunk);
|
||||
RootedValue chunkVal(cx, ObjectValue(*chunk));
|
||||
CHECK(ReadableStreamEnqueue(cx, stream, chunkVal));
|
||||
|
||||
CHECK(GetReadChunk(cx, request) == chunk);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamDefaultReaderRead)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableByteStreamDefaultReaderRead)
|
||||
{
|
||||
RootedObject stream(cx, NewByteStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default));
|
||||
CHECK(reader);
|
||||
|
||||
RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
|
||||
CHECK(request);
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
|
||||
size_t length = sizeof(test_buffer_data);
|
||||
RootedObject buffer(cx, JS_NewArrayBufferWithExternalContents(cx, length, test_buffer_data));
|
||||
CHECK(buffer);
|
||||
RootedObject chunk(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, length));
|
||||
CHECK(chunk);
|
||||
bool isShared;
|
||||
CHECK(!JS_IsDetachedArrayBufferObject(buffer));
|
||||
|
||||
CHECK(ReadableByteStreamEnqueueBuffer(cx, stream, chunk));
|
||||
|
||||
CHECK(JS_IsDetachedArrayBufferObject(buffer));
|
||||
RootedObject readChunk(cx, GetReadChunk(cx, request));
|
||||
CHECK(JS_IsUint8Array(readChunk));
|
||||
void* readBufferData;
|
||||
{
|
||||
JS::AutoCheckCannotGC autoNoGC(cx);
|
||||
readBufferData = JS_GetArrayBufferViewData(readChunk, &isShared, autoNoGC);
|
||||
}
|
||||
CHECK(readBufferData);
|
||||
CHECK(!memcmp(test_buffer_data, readBufferData, length));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableByteStreamDefaultReaderRead)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableByteStreamBYOBReaderRead)
|
||||
{
|
||||
RootedObject stream(cx, NewByteStream(cx));
|
||||
CHECK(stream);
|
||||
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::BYOB));
|
||||
CHECK(reader);
|
||||
|
||||
size_t length = sizeof(test_buffer_data);
|
||||
RootedObject targetArray(cx, JS_NewUint8Array(cx, length));
|
||||
bool isShared;
|
||||
|
||||
RootedObject request(cx, ReadableStreamBYOBReaderRead(cx, reader, targetArray));
|
||||
CHECK(request);
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
CHECK(JS_IsDetachedArrayBufferObject(JS_GetArrayBufferViewBuffer(cx, targetArray, &isShared)));
|
||||
|
||||
RootedObject buffer(cx, JS_NewArrayBufferWithExternalContents(cx, length, test_buffer_data));
|
||||
CHECK(buffer);
|
||||
CHECK(!JS_IsDetachedArrayBufferObject(buffer));
|
||||
|
||||
CHECK(ReadableByteStreamEnqueueBuffer(cx, stream, buffer));
|
||||
|
||||
CHECK(JS_IsDetachedArrayBufferObject(buffer));
|
||||
RootedObject readChunk(cx, GetReadChunk(cx, request));
|
||||
CHECK(JS_IsUint8Array(readChunk));
|
||||
void* readBufferData;
|
||||
{
|
||||
JS::AutoCheckCannotGC autoNoGC(cx);
|
||||
readBufferData = JS_GetArrayBufferViewData(readChunk, &isShared, autoNoGC);
|
||||
}
|
||||
CHECK(readBufferData);
|
||||
CHECK(!memcmp(test_buffer_data, readBufferData, length));
|
||||
// TODO: eliminate the memcpy that happens here.
|
||||
// CHECK(readBufferData == test_buffer_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableByteStreamBYOBReaderRead)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamDefaultReaderClose)
|
||||
{
|
||||
SetReadableStreamCallbacks(cx, &DataRequestCB, &WriteIntoRequestBufferCB,
|
||||
&CancelStreamCB, &StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB);
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default));
|
||||
CHECK(reader);
|
||||
|
||||
RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
|
||||
CHECK(request);
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
|
||||
CHECK(ReadableStreamClose(cx, stream));
|
||||
|
||||
bool done;
|
||||
RootedValue value(cx);
|
||||
CHECK(GetPromiseState(request) == PromiseState::Fulfilled);
|
||||
CHECK(GetIterResult(cx, request, &value, &done));
|
||||
CHECK(value.isUndefined());
|
||||
CHECK(done);
|
||||
|
||||
// The callbacks are only invoked for external streams.
|
||||
CHECK(!streamClosedCBCalled);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamDefaultReaderClose)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ReadableStreamDefaultReaderError)
|
||||
{
|
||||
ResetCallbacks();
|
||||
SetReadableStreamCallbacks(cx, &DataRequestCB, &WriteIntoRequestBufferCB,
|
||||
&CancelStreamCB, &StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB);
|
||||
RootedObject stream(cx, NewDefaultStream(cx));
|
||||
CHECK(stream);
|
||||
RootedObject reader(cx, ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default));
|
||||
CHECK(reader);
|
||||
|
||||
RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
|
||||
CHECK(request);
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
CHECK(ReadableStreamIsReadable(stream));
|
||||
RootedValue error(cx, Int32Value(42));
|
||||
CHECK(ReadableStreamError(cx, stream, error));
|
||||
|
||||
CHECK(GetPromiseState(request) == PromiseState::Rejected);
|
||||
RootedValue reason(cx, GetPromiseResult(request));
|
||||
CHECK(reason.isInt32());
|
||||
CHECK(reason.toInt32() == 42);
|
||||
|
||||
// The callbacks are only invoked for external streams.
|
||||
CHECK(!streamErroredCBCalled);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ReadableStreamDefaultReaderError)
|
||||
|
||||
static JSObject*
|
||||
NewExternalSourceStream(JSContext* cx, void* underlyingSource,
|
||||
RequestReadableStreamDataCallback dataRequestCallback,
|
||||
WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback,
|
||||
CancelReadableStreamCallback cancelCallback,
|
||||
ReadableStreamClosedCallback closedCallback,
|
||||
ReadableStreamErroredCallback erroredCallback,
|
||||
ReadableStreamFinalizeCallback finalizeCallback)
|
||||
{
|
||||
SetReadableStreamCallbacks(cx, dataRequestCallback, writeIntoReadRequestCallback,
|
||||
cancelCallback, closedCallback, erroredCallback,
|
||||
finalizeCallback);
|
||||
RootedObject stream(cx, NewReadableExternalSourceStreamObject(cx, underlyingSource));
|
||||
MOZ_ASSERT_IF(stream, IsReadableStream(stream));
|
||||
return stream;
|
||||
}
|
||||
|
||||
BEGIN_TEST(testReadableStream_CreateReadableByteStreamWithExternalSource)
|
||||
{
|
||||
ResetCallbacks();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB, &CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
CHECK(ReadableStreamGetMode(stream) == JS::ReadableStreamMode::ExternalSource);
|
||||
void* underlyingSource;
|
||||
CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream, &underlyingSource));
|
||||
CHECK(underlyingSource == &test_buffer_data);
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
ReadableStreamReleaseExternalUnderlyingSource(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_CreateReadableByteStreamWithExternalSource)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ExternalSourceCancel)
|
||||
{
|
||||
ResetCallbacks();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB, &CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
RootedValue reason(cx, Int32Value(42));
|
||||
CHECK(ReadableStreamCancel(cx, stream, reason));
|
||||
CHECK(cancelStreamCBCalled);
|
||||
CHECK(cancelStreamReason == reason);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ExternalSourceCancel)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ExternalSourceGetReader)
|
||||
{
|
||||
ResetCallbacks();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB, &CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
|
||||
RootedValue streamVal(cx, ObjectValue(*stream));
|
||||
CHECK(JS_SetProperty(cx, global, "stream", streamVal));
|
||||
RootedValue rval(cx);
|
||||
EVAL("stream.getReader()", &rval);
|
||||
CHECK(rval.isObject());
|
||||
RootedObject reader(cx, &rval.toObject());
|
||||
CHECK(IsReadableStreamDefaultReader(reader));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ExternalSourceGetReader)
|
||||
|
||||
BEGIN_TEST(testReadableStream_ExternalSourceUpdateAvailableData)
|
||||
{
|
||||
ResetCallbacks();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB, &CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
|
||||
ReadableStreamUpdateDataAvailableFromSource(cx, stream, 1024);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testReadableStream_ExternalSourceUpdateAvailableData)
|
||||
|
||||
struct ReadFromExternalSourceFixture : public JSAPITest
|
||||
{
|
||||
virtual ~ReadFromExternalSourceFixture() {}
|
||||
|
||||
bool readWithoutDataAvailable(const char* evalSrc, const char* evalSrc2,
|
||||
uint32_t writtenLength)
|
||||
{
|
||||
ResetCallbacks();
|
||||
definePrint();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB,
|
||||
&CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
js::RunJobs(cx);
|
||||
void* underlyingSource;
|
||||
CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream, &underlyingSource));
|
||||
CHECK(underlyingSource == &test_buffer_data);
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
ReadableStreamReleaseExternalUnderlyingSource(stream);
|
||||
|
||||
RootedValue streamVal(cx, ObjectValue(*stream));
|
||||
CHECK(JS_SetProperty(cx, global, "stream", streamVal));
|
||||
|
||||
RootedValue rval(cx);
|
||||
EVAL(evalSrc, &rval);
|
||||
CHECK(dataRequestCBCalled);
|
||||
CHECK(!writeIntoRequestBufferCBCalled);
|
||||
CHECK(rval.isObject());
|
||||
RootedObject promise(cx, &rval.toObject());
|
||||
CHECK(IsPromiseObject(promise));
|
||||
CHECK(GetPromiseState(promise) == PromiseState::Pending);
|
||||
|
||||
size_t length = sizeof(test_buffer_data);
|
||||
ReadableStreamUpdateDataAvailableFromSource(cx, stream, length);
|
||||
|
||||
CHECK(writeIntoRequestBufferCBCalled);
|
||||
CHECK(GetPromiseState(promise) == PromiseState::Fulfilled);
|
||||
RootedValue iterVal(cx);
|
||||
bool done;
|
||||
if (!GetIterResult(cx, promise, &iterVal, &done))
|
||||
return false;
|
||||
|
||||
CHECK(!done);
|
||||
RootedObject chunk(cx, &iterVal.toObject());
|
||||
CHECK(JS_IsUint8Array(chunk));
|
||||
|
||||
{
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
bool dummy;
|
||||
void* buffer = JS_GetArrayBufferViewData(chunk, &dummy, noGC);
|
||||
CHECK(!memcmp(buffer, test_buffer_data, writtenLength));
|
||||
}
|
||||
|
||||
dataRequestCBCalled = false;
|
||||
writeIntoRequestBufferCBCalled = false;
|
||||
EVAL(evalSrc2, &rval);
|
||||
CHECK(dataRequestCBCalled);
|
||||
CHECK(!writeIntoRequestBufferCBCalled);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readWithDataAvailable(const char* evalSrc, uint32_t writtenLength) {
|
||||
ResetCallbacks();
|
||||
definePrint();
|
||||
|
||||
RootedObject stream(cx, NewExternalSourceStream(cx, &test_buffer_data, &DataRequestCB,
|
||||
&WriteIntoRequestBufferCB, &CancelStreamCB,
|
||||
&StreamClosedCB, &StreamErroredCB,
|
||||
&FinalizeStreamCB));
|
||||
CHECK(stream);
|
||||
void* underlyingSource;
|
||||
CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream, &underlyingSource));
|
||||
CHECK(underlyingSource == &test_buffer_data);
|
||||
CHECK(ReadableStreamIsLocked(stream));
|
||||
ReadableStreamReleaseExternalUnderlyingSource(stream);
|
||||
|
||||
size_t length = sizeof(test_buffer_data);
|
||||
ReadableStreamUpdateDataAvailableFromSource(cx, stream, length);
|
||||
|
||||
RootedValue streamVal(cx, ObjectValue(*stream));
|
||||
CHECK(JS_SetProperty(cx, global, "stream", streamVal));
|
||||
|
||||
RootedValue rval(cx);
|
||||
EVAL(evalSrc, &rval);
|
||||
CHECK(writeIntoRequestBufferCBCalled);
|
||||
CHECK(rval.isObject());
|
||||
RootedObject promise(cx, &rval.toObject());
|
||||
CHECK(IsPromiseObject(promise));
|
||||
CHECK(GetPromiseState(promise) == PromiseState::Fulfilled);
|
||||
RootedValue iterVal(cx);
|
||||
bool done;
|
||||
if (!GetIterResult(cx, promise, &iterVal, &done))
|
||||
return false;
|
||||
|
||||
CHECK(!done);
|
||||
RootedObject chunk(cx, &iterVal.toObject());
|
||||
CHECK(JS_IsUint8Array(chunk));
|
||||
|
||||
{
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
bool dummy;
|
||||
void* buffer = JS_GetArrayBufferViewData(chunk, &dummy, noGC);
|
||||
CHECK(!memcmp(buffer, test_buffer_data, writtenLength));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable)
|
||||
{
|
||||
return readWithoutDataAvailable("r = stream.getReader(); r.read()", "r.read()", sizeof(test_buffer_data));
|
||||
}
|
||||
END_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable)
|
||||
|
||||
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceCloseWithPendingRead)
|
||||
{
|
||||
CHECK(readWithoutDataAvailable("r = stream.getReader(); request0 = r.read(); "
|
||||
"request1 = r.read(); request0", "r.read()",
|
||||
sizeof(test_buffer_data)));
|
||||
|
||||
RootedValue val(cx);
|
||||
CHECK(JS_GetProperty(cx, global, "request1", &val));
|
||||
CHECK(val.isObject());
|
||||
RootedObject request(cx, &val.toObject());
|
||||
CHECK(IsPromiseObject(request));
|
||||
CHECK(GetPromiseState(request) == PromiseState::Pending);
|
||||
|
||||
CHECK(JS_GetProperty(cx, global, "stream", &val));
|
||||
RootedObject stream(cx, &val.toObject());
|
||||
ReadableStreamClose(cx, stream);
|
||||
|
||||
val = GetPromiseResult(request);
|
||||
MOZ_ASSERT(val.isObject());
|
||||
RootedObject result(cx, &val.toObject());
|
||||
|
||||
JS_GetProperty(cx, result, "done", &val);
|
||||
CHECK(val.isBoolean());
|
||||
CHECK(val.toBoolean() == true);
|
||||
|
||||
JS_GetProperty(cx, result, "value", &val);
|
||||
CHECK(val.isUndefined());
|
||||
return true;
|
||||
}
|
||||
END_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceCloseWithPendingRead)
|
||||
|
||||
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadDefaultWithDataAvailable)
|
||||
{
|
||||
return readWithDataAvailable("r = stream.getReader(); r.read()", sizeof(test_buffer_data));
|
||||
}
|
||||
END_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadDefaultWithDataAvailable)
|
||||
|
||||
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadBYOBWithoutDataAvailable)
|
||||
{
|
||||
return readWithoutDataAvailable("r = stream.getReader({mode: 'byob'}); r.read(new Uint8Array(63))", "r.read(new Uint8Array(10))", 10);
|
||||
}
|
||||
END_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadBYOBWithoutDataAvailable)
|
||||
|
||||
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadBYOBWithDataAvailable)
|
||||
{
|
||||
return readWithDataAvailable("r = stream.getReader({mode: 'byob'}); r.read(new Uint8Array(10))", 10);
|
||||
}
|
||||
END_FIXTURE_TEST(ReadFromExternalSourceFixture,
|
||||
testReadableStream_ExternalSourceReadBYOBWithDataAvailable)
|
@ -83,10 +83,6 @@ JSObject* JSAPITest::createGlobal(JSPrincipals* principals)
|
||||
/* Create the global object. */
|
||||
JS::RootedObject newGlobal(cx);
|
||||
JS::CompartmentOptions options;
|
||||
#ifdef ENABLE_STREAMS
|
||||
options.creationOptions().setStreamsEnabled(true);
|
||||
#endif
|
||||
printf("enabled\n");
|
||||
options.behaviors().setVersion(JSVERSION_LATEST);
|
||||
newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook,
|
||||
options);
|
||||
|
364
js/src/jsapi.cpp
364
js/src/jsapi.cpp
@ -49,7 +49,6 @@
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/Promise.h"
|
||||
#include "builtin/RegExp.h"
|
||||
#include "builtin/Stream.h"
|
||||
#include "builtin/SymbolObject.h"
|
||||
#ifdef ENABLE_SIMD
|
||||
# include "builtin/SIMD.h"
|
||||
@ -5212,6 +5211,7 @@ CallOriginalPromiseThenImpl(JSContext* cx, JS::HandleObject promiseObj,
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
@ -5253,368 +5253,6 @@ JS::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
|
||||
return js::GetWaitForAllPromise(cx, promises);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::NewReadableDefaultStreamObject(JSContext* cx,
|
||||
JS::HandleObject underlyingSource /* = nullptr */,
|
||||
JS::HandleFunction size /* = nullptr */,
|
||||
double highWaterMark /* = 1 */,
|
||||
JS::HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
RootedObject source(cx, underlyingSource);
|
||||
if (!source) {
|
||||
source = NewBuiltinClassInstance<PlainObject>(cx);
|
||||
if (!source)
|
||||
return nullptr;
|
||||
}
|
||||
RootedValue sourceVal(cx, ObjectValue(*source));
|
||||
RootedValue sizeVal(cx, size ? ObjectValue(*size) : UndefinedValue());
|
||||
RootedValue highWaterMarkVal(cx, NumberValue(highWaterMark));
|
||||
return ReadableStream::createDefaultStream(cx, sourceVal, sizeVal, highWaterMarkVal, proto);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::NewReadableByteStreamObject(JSContext* cx,
|
||||
JS::HandleObject underlyingSource /* = nullptr */,
|
||||
double highWaterMark /* = 1 */,
|
||||
JS::HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
RootedObject source(cx, underlyingSource);
|
||||
if (!source) {
|
||||
source = NewBuiltinClassInstance<PlainObject>(cx);
|
||||
if (!source)
|
||||
return nullptr;
|
||||
}
|
||||
RootedValue sourceVal(cx, ObjectValue(*source));
|
||||
RootedValue highWaterMarkVal(cx, NumberValue(highWaterMark));
|
||||
return ReadableStream::createByteStream(cx, sourceVal, highWaterMarkVal, proto);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS::SetReadableStreamCallbacks(JSContext* cx,
|
||||
JS::RequestReadableStreamDataCallback dataRequestCallback,
|
||||
JS::WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback,
|
||||
JS::CancelReadableStreamCallback cancelCallback,
|
||||
JS::ReadableStreamClosedCallback closedCallback,
|
||||
JS::ReadableStreamErroredCallback erroredCallback,
|
||||
JS::ReadableStreamFinalizeCallback finalizeCallback)
|
||||
{
|
||||
MOZ_ASSERT(dataRequestCallback);
|
||||
MOZ_ASSERT(writeIntoReadRequestCallback);
|
||||
MOZ_ASSERT(cancelCallback);
|
||||
MOZ_ASSERT(closedCallback);
|
||||
MOZ_ASSERT(erroredCallback);
|
||||
MOZ_ASSERT(finalizeCallback);
|
||||
|
||||
JSRuntime* rt = cx->runtime();
|
||||
|
||||
MOZ_ASSERT(!rt->readableStreamDataRequestCallback);
|
||||
MOZ_ASSERT(!rt->readableStreamWriteIntoReadRequestCallback);
|
||||
MOZ_ASSERT(!rt->readableStreamCancelCallback);
|
||||
MOZ_ASSERT(!rt->readableStreamClosedCallback);
|
||||
MOZ_ASSERT(!rt->readableStreamErroredCallback);
|
||||
MOZ_ASSERT(!rt->readableStreamFinalizeCallback);
|
||||
|
||||
rt->readableStreamDataRequestCallback = dataRequestCallback;
|
||||
rt->readableStreamWriteIntoReadRequestCallback = writeIntoReadRequestCallback;
|
||||
rt->readableStreamCancelCallback = cancelCallback;
|
||||
rt->readableStreamClosedCallback = closedCallback;
|
||||
rt->readableStreamErroredCallback = erroredCallback;
|
||||
rt->readableStreamFinalizeCallback = finalizeCallback;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::HasReadableStreamCallbacks(JSContext* cx)
|
||||
{
|
||||
return cx->runtime()->readableStreamDataRequestCallback;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::NewReadableExternalSourceStreamObject(JSContext* cx, void* underlyingSource,
|
||||
uint8_t flags /* = 0 */,
|
||||
HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
JSRuntime* rt = cx->runtime();
|
||||
MOZ_ASSERT(rt->readableStreamDataRequestCallback);
|
||||
MOZ_ASSERT(rt->readableStreamWriteIntoReadRequestCallback);
|
||||
MOZ_ASSERT(rt->readableStreamCancelCallback);
|
||||
MOZ_ASSERT(rt->readableStreamClosedCallback);
|
||||
MOZ_ASSERT(rt->readableStreamErroredCallback);
|
||||
MOZ_ASSERT(rt->readableStreamFinalizeCallback);
|
||||
#endif // DEBUG
|
||||
|
||||
return ReadableStream::createExternalSourceStream(cx, underlyingSource, flags, proto);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint8_t)
|
||||
JS::ReadableStreamGetEmbeddingFlags(const JSObject* stream)
|
||||
{
|
||||
return stream->as<ReadableStream>().embeddingFlags();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStream(const JSObject* obj)
|
||||
{
|
||||
return obj->is<ReadableStream>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStreamReader(const JSObject* obj)
|
||||
{
|
||||
return obj->is<ReadableStreamDefaultReader>() || obj->is<ReadableStreamBYOBReader>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStreamDefaultReader(const JSObject* obj)
|
||||
{
|
||||
return obj->is<ReadableStreamDefaultReader>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsReadableStreamBYOBReader(const JSObject* obj)
|
||||
{
|
||||
return obj->is<ReadableStreamBYOBReader>();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamIsReadable(const JSObject* stream)
|
||||
{
|
||||
return stream->as<ReadableStream>().readable();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamIsLocked(const JSObject* stream)
|
||||
{
|
||||
return stream->as<ReadableStream>().locked();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamIsDisturbed(const JSObject* stream)
|
||||
{
|
||||
return stream->as<ReadableStream>().disturbed();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::ReadableStreamCancel(JSContext* cx, HandleObject streamObj, HandleValue reason)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
assertSameCompartment(cx, reason);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return ReadableStream::cancel(cx, stream, reason);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::ReadableStreamMode)
|
||||
JS::ReadableStreamGetMode(const JSObject* stream)
|
||||
{
|
||||
return stream->as<ReadableStream>().mode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::ReadableStreamGetReader(JSContext* cx, HandleObject streamObj, ReadableStreamReaderMode mode)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return ReadableStream::getReader(cx, stream, mode);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamGetExternalUnderlyingSource(JSContext* cx, HandleObject streamObj, void** source)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return ReadableStream::getExternalSource(cx, stream, source);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::ReadableStreamReleaseExternalUnderlyingSource(JSObject* stream)
|
||||
{
|
||||
stream->as<ReadableStream>().releaseExternalSource();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamUpdateDataAvailableFromSource(JSContext* cx, JS::HandleObject streamObj,
|
||||
uint32_t availableData)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return ReadableStream::updateDataAvailableFromSource(cx, stream, availableData);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamTee(JSContext* cx, HandleObject streamObj,
|
||||
MutableHandleObject branch1Obj, MutableHandleObject branch2Obj)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
Rooted<ReadableStream*> branch1Stream(cx);
|
||||
Rooted<ReadableStream*> branch2Stream(cx);
|
||||
|
||||
if (!ReadableStream::tee(cx, stream, false, &branch1Stream, &branch2Stream))
|
||||
return false;
|
||||
|
||||
branch1Obj.set(branch1Stream);
|
||||
branch2Obj.set(branch2Stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::ReadableStreamGetDesiredSize(JSObject* streamObj, bool* hasValue, double* value)
|
||||
{
|
||||
streamObj->as<ReadableStream>().desiredSize(hasValue, value);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamClose(JSContext* cx, HandleObject streamObj)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return ReadableStream::close(cx, stream);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamEnqueue(JSContext* cx, HandleObject streamObj, HandleValue chunk)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
assertSameCompartment(cx, chunk);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
if (stream->mode() != JS::ReadableStreamMode::Default) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER,
|
||||
"JS::ReadableStreamEnqueue");
|
||||
return false;
|
||||
}
|
||||
return ReadableStream::enqueue(cx, stream, chunk);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableByteStreamEnqueueBuffer(JSContext* cx, HandleObject streamObj, HandleObject chunkObj)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
assertSameCompartment(cx, chunkObj);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
if (stream->mode() != JS::ReadableStreamMode::Byte) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER,
|
||||
"JS::ReadableByteStreamEnqueueBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx);
|
||||
if (chunkObj->is<ArrayBufferViewObject>()) {
|
||||
bool dummy;
|
||||
buffer = &JS_GetArrayBufferViewBuffer(cx, chunkObj, &dummy)->as<ArrayBufferObject>();
|
||||
} else if (chunkObj->is<ArrayBufferObject>()) {
|
||||
buffer = &chunkObj->as<ArrayBufferObject>();
|
||||
} else {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK,
|
||||
"JS::ReadableByteStreamEnqueueBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadableStream::enqueueBuffer(cx, stream, buffer);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamError(JSContext* cx, HandleObject streamObj, HandleValue error)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, streamObj);
|
||||
assertSameCompartment(cx, error);
|
||||
|
||||
Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
|
||||
return js::ReadableStream::error(cx, stream, error);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamReaderIsClosed(const JSObject* reader)
|
||||
{
|
||||
return js::ReadableStreamReaderIsClosed(reader);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamReaderCancel(JSContext* cx, HandleObject reader, HandleValue reason)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, reader);
|
||||
assertSameCompartment(cx, reason);
|
||||
|
||||
return js::ReadableStreamReaderCancel(cx, reader, reason);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::ReadableStreamReaderReleaseLock(JSContext* cx, HandleObject reader)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, reader);
|
||||
|
||||
return js::ReadableStreamReaderReleaseLock(cx, reader);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::ReadableStreamDefaultReaderRead(JSContext* cx, HandleObject readerObj)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, readerObj);
|
||||
|
||||
Rooted<ReadableStreamDefaultReader*> reader(cx, &readerObj->as<ReadableStreamDefaultReader>());
|
||||
return js::ReadableStreamDefaultReader::read(cx, reader);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::ReadableStreamBYOBReaderRead(JSContext* cx, HandleObject readerObj, HandleObject viewObj)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, readerObj);
|
||||
assertSameCompartment(cx, viewObj);
|
||||
|
||||
Rooted<ReadableStreamBYOBReader*> reader(cx, &readerObj->as<ReadableStreamBYOBReader>());
|
||||
Rooted<ArrayBufferViewObject*> view(cx, &viewObj->as<ArrayBufferViewObject>());
|
||||
return js::ReadableStreamBYOBReader::read(cx, reader, view);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetAsyncTaskCallbacks(JSContext* cx, JS::StartAsyncTaskCallback start,
|
||||
JS::FinishAsyncTaskCallback finish)
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include "js/Realm.h"
|
||||
#include "js/RefCounted.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Stream.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "js/Utility.h"
|
||||
|
@ -125,7 +125,6 @@ EXPORTS.js += [
|
||||
'../public/Result.h',
|
||||
'../public/RootingAPI.h',
|
||||
'../public/SliceBudget.h',
|
||||
'../public/Stream.h',
|
||||
'../public/StructuredClone.h',
|
||||
'../public/SweepingAPI.h',
|
||||
'../public/TraceKind.h',
|
||||
|
@ -17,8 +17,6 @@
|
||||
macro(anonymous, anonymous, "anonymous") \
|
||||
macro(Any, Any, "Any") \
|
||||
macro(apply, apply, "apply") \
|
||||
macro(AcquireReadableStreamBYOBReader, AcquireReadableStreamBYOBReader, "AcquireReadableStreamBYOBReader") \
|
||||
macro(AcquireReadableStreamDefaultReader, AcquireReadableStreamDefaultReader, "AcquireReadableStreamDefaultReader") \
|
||||
macro(arguments, arguments, "arguments") \
|
||||
macro(ArrayBufferSpecies, ArrayBufferSpecies, "ArrayBufferSpecies") \
|
||||
macro(ArrayIterator, ArrayIterator, "Array Iterator") \
|
||||
@ -299,50 +297,6 @@
|
||||
macro(prototype, prototype, "prototype") \
|
||||
macro(proxy, proxy, "proxy") \
|
||||
macro(raw, raw, "raw") \
|
||||
macro(ReadableByteStreamControllerGetDesiredSize, \
|
||||
ReadableByteStreamControllerGetDesiredSize, \
|
||||
"ReadableByteStreamControllerGetDesiredSize") \
|
||||
macro(ReadableByteStreamController_close, \
|
||||
ReadableByteStreamController_close, \
|
||||
"ReadableByteStreamController_close") \
|
||||
macro(ReadableByteStreamController_enqueue, \
|
||||
ReadableByteStreamController_enqueue, \
|
||||
"ReadableByteStreamController_enqueue") \
|
||||
macro(ReadableByteStreamController_error, \
|
||||
ReadableByteStreamController_error, \
|
||||
"ReadableByteStreamController_error") \
|
||||
macro(ReadableStreamBYOBReader_cancel, \
|
||||
ReadableStreamBYOBReader_cancel, \
|
||||
"ReadableStreamBYOBReader_cancel") \
|
||||
macro(ReadableStreamBYOBReader_read, \
|
||||
ReadableStreamBYOBReader_read, \
|
||||
"ReadableStreamBYOBReader_read") \
|
||||
macro(ReadableStreamBYOBReader_releaseLock, \
|
||||
ReadableStreamBYOBReader_releaseLock, \
|
||||
"ReadableStreamBYOBReader_releaseLock") \
|
||||
macro(ReadableStream_cancel, ReadableStream_cancel, "ReadableStream_cancel") \
|
||||
macro(ReadableStreamDefaultControllerGetDesiredSize, \
|
||||
ReadableStreamDefaultControllerGetDesiredSize, \
|
||||
"ReadableStreamDefaultControllerGetDesiredSize") \
|
||||
macro(ReadableStreamDefaultController_close, \
|
||||
ReadableStreamDefaultController_close, \
|
||||
"ReadableStreamDefaultController_close") \
|
||||
macro(ReadableStreamDefaultController_enqueue, \
|
||||
ReadableStreamDefaultController_enqueue, \
|
||||
"ReadableStreamDefaultController_enqueue") \
|
||||
macro(ReadableStreamDefaultController_error, \
|
||||
ReadableStreamDefaultController_error, \
|
||||
"ReadableStreamDefaultController_error") \
|
||||
macro(ReadableStreamDefaultReader_cancel, \
|
||||
ReadableStreamDefaultReader_cancel, \
|
||||
"ReadableStreamDefaultReader_cancel") \
|
||||
macro(ReadableStreamDefaultReader_read, \
|
||||
ReadableStreamDefaultReader_read, \
|
||||
"ReadableStreamDefaultReader_read") \
|
||||
macro(ReadableStreamDefaultReader_releaseLock, \
|
||||
ReadableStreamDefaultReader_releaseLock, \
|
||||
"ReadableStreamDefaultReader_releaseLock") \
|
||||
macro(ReadableStreamTee, ReadableStreamTee, "ReadableStreamTee") \
|
||||
macro(reason, reason, "reason") \
|
||||
macro(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \
|
||||
macro(RegExpFlagsGetter, RegExpFlagsGetter, "RegExpFlagsGetter") \
|
||||
|
@ -108,12 +108,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
startAsyncTaskCallback(nullptr),
|
||||
finishAsyncTaskCallback(nullptr),
|
||||
promiseTasksToDestroy(mutexid::PromiseTaskPtrVector),
|
||||
readableStreamDataRequestCallback(nullptr),
|
||||
readableStreamWriteIntoReadRequestCallback(nullptr),
|
||||
readableStreamCancelCallback(nullptr),
|
||||
readableStreamClosedCallback(nullptr),
|
||||
readableStreamErroredCallback(nullptr),
|
||||
readableStreamFinalizeCallback(nullptr),
|
||||
hadOutOfMemory(false),
|
||||
allowRelazificationForTesting(false),
|
||||
destroyCompartmentCallback(nullptr),
|
||||
|
@ -476,13 +476,6 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
||||
void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
|
||||
void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
|
||||
|
||||
js::UnprotectedData<JS::RequestReadableStreamDataCallback> readableStreamDataRequestCallback;
|
||||
js::UnprotectedData<JS::WriteIntoReadRequestBufferCallback> readableStreamWriteIntoReadRequestCallback;
|
||||
js::UnprotectedData<JS::CancelReadableStreamCallback> readableStreamCancelCallback;
|
||||
js::UnprotectedData<JS::ReadableStreamClosedCallback> readableStreamClosedCallback;
|
||||
js::UnprotectedData<JS::ReadableStreamErroredCallback> readableStreamErroredCallback;
|
||||
js::UnprotectedData<JS::ReadableStreamFinalizeCallback> readableStreamFinalizeCallback;
|
||||
|
||||
/* Had an out-of-memory error which did not populate an exception. */
|
||||
mozilla::Atomic<bool> hadOutOfMemory;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user