Bug 1732010 [wpt PR 30847] - Fix incorrect svg-document-styles tests., a=testonly
[gecko.git] / js / public / Stream.h
blobba4c3c1c49e94730d0ba5d903f1db2858d415da7
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JSAPI functions and callbacks related to WHATWG Stream objects.
10 * Much of the API here mirrors the standard algorithms and standard JS methods
11 * of the objects defined in the Streams standard. One difference is that the
12 * functionality of the JS controller object is exposed to C++ as functions
13 * taking ReadableStream instances instead, for convenience.
16 #ifndef js_Stream_h
17 #define js_Stream_h
19 #include <stddef.h>
21 #include "jstypes.h"
23 #include "js/RootingAPI.h"
24 #include "js/TypeDecls.h"
26 struct JSClass;
28 namespace JS {
30 /**
31 * Abstract base class for external underlying sources.
33 * The term "underlying source" is defined in the Streams spec:
34 * https://streams.spec.whatwg.org/#underlying-source
36 * A `ReadableStreamUnderlyingSource` is an underlying source that is
37 * implemented in C++ rather than JS. It can be passed to
38 * `JS::NewReadableExternalSourceStreamObject` to create a custom,
39 * embedding-defined ReadableStream.
41 * There are several API difference between this class and the standard API for
42 * underlying sources implemented in JS:
44 * - JS underlying sources can be either byte sources or non-byte sources.
45 * External underlying source are always byte sources.
47 * - The C++ API does not bother with controller objects. Instead of using
48 * controller methods, the underlying source directly calls API functions
49 * like JS::ReadableStream{UpdateDataAvailableFromSource,Close,Error}.
51 * - External readable streams are optimized to allow the embedding to
52 * interact with them with a minimum of overhead: chunks aren't enqueued as
53 * individual typed arrays; instead, the embedding only updates the amount
54 * of data available using
55 * JS::ReadableStreamUpdateDataAvailableFromSource. When JS requests data
56 * from a reader, writeIntoReadRequestBuffer is invoked, asking the
57 * embedding to write data directly into the buffer we're about to hand to
58 * JS.
60 * - The C++ API provides extra callbacks onClosed() and onErrored().
62 * - This class has a `finalize()` method, because C++ cares about lifetimes.
64 * Additionally, ReadableStreamGetExternalUnderlyingSource can be used to get
65 * the pointer to the underlying source. This locks the stream until it is
66 * released again using JS::ReadableStreamReleaseExternalUnderlyingSource.
68 * Embeddings can use this to optimize away the JS `ReadableStream` overhead
69 * when an embedding-defined C++ stream is passed to an embedding-defined C++
70 * consumer. For example, consider a ServiceWorker piping a `fetch` Response
71 * body to a TextDecoder. Instead of copying chunks of data into JS typed array
72 * buffers and creating a Promise per chunk, only to immediately resolve the
73 * Promises and read the data out again, the embedding can directly feed the
74 * incoming data to the TextDecoder.
76 * Compartment safety: All methods (except `finalize`) receive `cx` and
77 * `stream` arguments. SpiderMonkey enters the realm of the stream object
78 * before invoking these methods, so `stream` is never a wrapper. Other
79 * arguments may be wrappers.
81 class JS_PUBLIC_API ReadableStreamUnderlyingSource {
82 public:
83 virtual ~ReadableStreamUnderlyingSource() = default;
85 /**
86 * Invoked whenever a reader desires more data from this source.
88 * The given `desiredSize` is the absolute size, not a delta from the
89 * previous desired size.
91 virtual void requestData(JSContext* cx, HandleObject stream,
92 size_t desiredSize) = 0;
94 /**
95 * Invoked to cause the embedding to fill the given `buffer` with data from
96 * this underlying source.
98 * This is called only after the embedding has updated the amount of data
99 * available using JS::ReadableStreamUpdateDataAvailableFromSource. If at
100 * least one read request is pending when
101 * JS::ReadableStreamUpdateDataAvailableFromSource is called, this method
102 * is invoked immediately from under the call to
103 * JS::ReadableStreamUpdateDataAvailableFromSource. If not, it is invoked
104 * if and when a new read request is made.
106 * Note: This method *must not cause GC*, because that could potentially
107 * invalidate the `buffer` pointer.
109 virtual void writeIntoReadRequestBuffer(JSContext* cx, HandleObject stream,
110 void* buffer, size_t length,
111 size_t* bytesWritten) = 0;
114 * Invoked in reaction to the ReadableStream being canceled. This is
115 * equivalent to the `cancel` method on non-external underlying sources
116 * provided to the ReadableStream constructor in JavaScript.
118 * The underlying source may free up some resources in this method, but
119 * `*this` must not be destroyed until `finalize()` is called.
121 * The given `reason` is the JS::Value that was passed as an argument to
122 * ReadableStream#cancel().
124 * The returned JS::Value will be used to resolve the Promise returned by
125 * ReadableStream#cancel().
127 virtual Value cancel(JSContext* cx, HandleObject stream,
128 HandleValue reason) = 0;
131 * Invoked when the associated ReadableStream becomes closed.
133 * The underlying source may free up some resources in this method, but
134 * `*this` must not be destroyed until `finalize()` is called.
136 virtual void onClosed(JSContext* cx, HandleObject stream) = 0;
139 * Invoked when the associated ReadableStream becomes errored.
141 * The underlying source may free up some resources in this method, but
142 * `*this` must not be destroyed until `finalize()` is called.
144 virtual void onErrored(JSContext* cx, HandleObject stream,
145 HandleValue reason) = 0;
148 * Invoked when the associated ReadableStream object is finalized. The
149 * stream object is not passed as an argument, as it might not be in a
150 * valid state anymore.
152 * Note: Finalization can happen on a background thread, so the embedding
153 * must be prepared for `finalize()` to be invoked from any thread.
155 virtual void finalize() = 0;
159 * Returns a new instance of the ReadableStream builtin class in the current
160 * compartment, configured as a default stream.
161 * If a |proto| is passed, that gets set as the instance's [[Prototype]]
162 * instead of the original value of |ReadableStream.prototype|.
164 extern JS_PUBLIC_API JSObject* NewReadableDefaultStreamObject(
165 JSContext* cx, HandleObject underlyingSource = nullptr,
166 HandleFunction size = nullptr, double highWaterMark = 1,
167 HandleObject proto = nullptr);
170 * Returns a new instance of the ReadableStream builtin class in the current
171 * compartment.
173 * The instance is a byte stream backed by an embedding-provided underlying
174 * source, using the virtual methods of `underlyingSource` as callbacks. The
175 * embedding must ensure that `*underlyingSource` lives as long as the new
176 * stream object. The JS engine will call the finalize() method when the stream
177 * object is destroyed.
179 * `nsISupportsObject_alreadyAddreffed` is an optional pointer that can be used
180 * to make the new stream participate in Gecko's cycle collection. Here are the
181 * rules for using this parameter properly:
183 * - `*underlyingSource` must not be a cycle-collected object. (It would lead
184 * to memory leaks as the cycle collector would not be able to collect
185 * cycles containing that object.)
187 * - `*underlyingSource` must not contain nsCOMPtrs that point to cycle-
188 * collected objects. (Same reason.)
190 * - `*underlyingSource` may contain a pointer to a single cycle-collected
191 * object.
193 * - The pointer may be stored in `*underlyingSource` as a raw pointer.
195 * - The pointer to the nsISupports interface of the same object must be
196 * passed as the `nsISupportsObject_alreadyAddreffed` parameter to this
197 * function. (This is how the cycle collector knows about it, so omitting
198 * this would again cause leaks.)
200 * If `proto` is non-null, it is used as the instance's [[Prototype]] instead
201 * of the original value of `ReadableStream.prototype`.
203 extern JS_PUBLIC_API JSObject* NewReadableExternalSourceStreamObject(
204 JSContext* cx, ReadableStreamUnderlyingSource* underlyingSource,
205 void* nsISupportsObject_alreadyAddreffed = nullptr,
206 HandleObject proto = nullptr);
209 * Returns the embedding-provided underlying source of the given |stream|.
211 * Can be used to optimize operations if both the underlying source and the
212 * intended sink are embedding-provided. In that case it might be
213 * preferrable to pipe data directly from source to sink without interacting
214 * with the stream at all.
216 * Locks the stream until ReadableStreamReleaseExternalUnderlyingSource is
217 * called.
219 * Throws an exception if the stream is locked, i.e. if a reader has been
220 * acquired for the stream, or if ReadableStreamGetExternalUnderlyingSource
221 * has been used previously without releasing the external source again.
223 * Throws an exception if the stream isn't readable, i.e if it is errored or
224 * closed. This is different from ReadableStreamGetReader because we don't
225 * have a Promise to resolve/reject, which a reader provides.
227 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
228 * for one.
230 * Asserts that the stream has an embedding-provided underlying source.
232 extern JS_PUBLIC_API bool ReadableStreamGetExternalUnderlyingSource(
233 JSContext* cx, HandleObject stream,
234 ReadableStreamUnderlyingSource** source);
237 * Releases the embedding-provided underlying source of the given |stream|,
238 * returning the stream into an unlocked state.
240 * Asserts that the stream was locked through
241 * ReadableStreamGetExternalUnderlyingSource.
243 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
244 * for one.
246 * Asserts that the stream has an embedding-provided underlying source.
248 extern JS_PUBLIC_API bool ReadableStreamReleaseExternalUnderlyingSource(
249 JSContext* cx, HandleObject stream);
252 * Update the amount of data available at the underlying source of the given
253 * |stream|.
255 * Can only be used for streams with an embedding-provided underlying source.
256 * The JS engine will use the given value to satisfy read requests for the
257 * stream by invoking the writeIntoReadRequestBuffer method.
259 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
260 * for one.
262 extern JS_PUBLIC_API bool ReadableStreamUpdateDataAvailableFromSource(
263 JSContext* cx, HandleObject stream, uint32_t availableData);
266 * Break the cycle between this object and the
267 * nsISupportsObject_alreadyAddreffed passed in
268 * NewReadableExternalSourceStreamObject().
270 extern JS_PUBLIC_API void ReadableStreamReleaseCCObject(JSObject* stream);
273 * Returns true if the given object is a ReadableStream object or an
274 * unwrappable wrapper for one, false otherwise.
276 extern JS_PUBLIC_API bool IsReadableStream(JSObject* obj);
279 * Returns true if the given object is a ReadableStreamDefaultReader or
280 * ReadableStreamBYOBReader object or an unwrappable wrapper for one, false
281 * otherwise.
283 extern JS_PUBLIC_API bool IsReadableStreamReader(JSObject* obj);
286 * Returns true if the given object is a ReadableStreamDefaultReader object
287 * or an unwrappable wrapper for one, false otherwise.
289 extern JS_PUBLIC_API bool IsReadableStreamDefaultReader(JSObject* obj);
291 enum class ReadableStreamMode { Default, Byte, ExternalSource };
294 * Returns the stream's ReadableStreamMode. If the mode is |Byte| or
295 * |ExternalSource|, it's possible to acquire a BYOB reader for more optimized
296 * operations.
298 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
299 * for one.
301 extern JS_PUBLIC_API bool ReadableStreamGetMode(JSContext* cx,
302 HandleObject stream,
303 ReadableStreamMode* mode);
305 enum class ReadableStreamReaderMode { Default };
308 * Returns true if the given ReadableStream is readable, false if not.
310 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
311 * for one.
313 extern JS_PUBLIC_API bool ReadableStreamIsReadable(JSContext* cx,
314 HandleObject stream,
315 bool* result);
318 * Returns true if the given ReadableStream is locked, false if not.
320 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
321 * for one.
323 extern JS_PUBLIC_API bool ReadableStreamIsLocked(JSContext* cx,
324 HandleObject stream,
325 bool* result);
328 * Returns true if the given ReadableStream is disturbed, false if not.
330 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
331 * for one.
333 extern JS_PUBLIC_API bool ReadableStreamIsDisturbed(JSContext* cx,
334 HandleObject stream,
335 bool* result);
338 * Cancels the given ReadableStream with the given reason and returns a
339 * Promise resolved according to the result.
341 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
342 * for one.
344 extern JS_PUBLIC_API JSObject* ReadableStreamCancel(JSContext* cx,
345 HandleObject stream,
346 HandleValue reason);
349 * Creates a reader of the type specified by the mode option and locks the
350 * stream to the new reader.
352 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
353 * for one. The returned object will always be created in the
354 * current cx compartment.
356 extern JS_PUBLIC_API JSObject* ReadableStreamGetReader(
357 JSContext* cx, HandleObject stream, ReadableStreamReaderMode mode);
360 * Tees the given ReadableStream and stores the two resulting streams in
361 * outparams. Returns false if the operation fails, e.g. because the stream is
362 * locked.
364 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
365 * for one.
367 extern JS_PUBLIC_API bool ReadableStreamTee(JSContext* cx, HandleObject stream,
368 MutableHandleObject branch1Stream,
369 MutableHandleObject branch2Stream);
372 * Retrieves the desired combined size of additional chunks to fill the given
373 * ReadableStream's queue. Stores the result in |value| and sets |hasValue| to
374 * true on success, returns false on failure.
376 * If the stream is errored, the call will succeed but no value will be stored
377 * in |value| and |hasValue| will be set to false.
379 * Note: This is semantically equivalent to the |desiredSize| getter on
380 * the stream controller's prototype in JS. We expose it with the stream
381 * itself as a target for simplicity.
383 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
384 * for one.
386 extern JS_PUBLIC_API bool ReadableStreamGetDesiredSize(JSContext* cx,
387 JSObject* stream,
388 bool* hasValue,
389 double* value);
392 * Close the given ReadableStream. This is equivalent to `controller.close()`
393 * in JS.
395 * This can fail with or without an exception pending under a variety of
396 * circumstances. On failure, the stream may or may not be closed, and
397 * downstream consumers may or may not have been notified.
399 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
400 * for one.
402 extern JS_PUBLIC_API bool ReadableStreamClose(JSContext* cx,
403 HandleObject stream);
406 * Returns true if the given ReadableStream reader is locked, false otherwise.
408 * Asserts that |reader| is a ReadableStreamDefaultReader or
409 * ReadableStreamBYOBReader object or an unwrappable wrapper for one.
411 extern JS_PUBLIC_API bool ReadableStreamReaderIsClosed(JSContext* cx,
412 HandleObject reader,
413 bool* result);
416 * Enqueues the given chunk in the given ReadableStream.
418 * Throws a TypeError and returns false if the enqueing operation fails.
420 * Note: This is semantically equivalent to the |enqueue| method on
421 * the stream controller's prototype in JS. We expose it with the stream
422 * itself as a target for simplicity.
424 * If the ReadableStream has an underlying byte source, the given chunk must
425 * be a typed array or a DataView. Consider using
426 * ReadableByteStreamEnqueueBuffer.
428 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
429 * for one.
431 extern JS_PUBLIC_API bool ReadableStreamEnqueue(JSContext* cx,
432 HandleObject stream,
433 HandleValue chunk);
436 * Errors the given ReadableStream, causing all future interactions to fail
437 * with the given error value.
439 * Throws a TypeError and returns false if the erroring operation fails.
441 * Note: This is semantically equivalent to the |error| method on
442 * the stream controller's prototype in JS. We expose it with the stream
443 * itself as a target for simplicity.
445 * Asserts that |stream| is a ReadableStream object or an unwrappable wrapper
446 * for one.
448 extern JS_PUBLIC_API bool ReadableStreamError(JSContext* cx,
449 HandleObject stream,
450 HandleValue error);
453 * C++ equivalent of `reader.cancel(reason)`
454 * (both <https://streams.spec.whatwg.org/#default-reader-cancel> and
455 * <https://streams.spec.whatwg.org/#byob-reader-cancel>).
457 * `reader` must be a stream reader created using `JS::ReadableStreamGetReader`
458 * or an unwrappable wrapper for one. (This function is meant to support using
459 * C++ to read from streams. It's not meant to allow C++ code to operate on
460 * readers created by scripts.)
462 extern JS_PUBLIC_API bool ReadableStreamReaderCancel(JSContext* cx,
463 HandleObject reader,
464 HandleValue reason);
467 * C++ equivalent of `reader.releaseLock()`
468 * (both <https://streams.spec.whatwg.org/#default-reader-release-lock> and
469 * <https://streams.spec.whatwg.org/#byob-reader-release-lock>).
471 * `reader` must be a stream reader created using `JS::ReadableStreamGetReader`
472 * or an unwrappable wrapper for one.
474 extern JS_PUBLIC_API bool ReadableStreamReaderReleaseLock(JSContext* cx,
475 HandleObject reader);
478 * C++ equivalent of the `reader.read()` method on default readers
479 * (<https://streams.spec.whatwg.org/#default-reader-read>).
481 * The result is a new Promise object, or null on OOM.
483 * `reader` must be the result of calling `JS::ReadableStreamGetReader` with
484 * `ReadableStreamReaderMode::Default` mode, or an unwrappable wrapper for such
485 * a reader.
487 extern JS_PUBLIC_API JSObject* ReadableStreamDefaultReaderRead(
488 JSContext* cx, HandleObject reader);
490 class JS_PUBLIC_API WritableStreamUnderlyingSink {
491 public:
492 virtual ~WritableStreamUnderlyingSink() = default;
495 * Invoked when the associated WritableStream object is finalized. The
496 * stream object is not passed as an argument, as it might not be in a
497 * valid state anymore.
499 * Note: Finalization can happen on a background thread, so the embedding
500 * must be prepared for `finalize()` to be invoked from any thread.
502 virtual void finalize() = 0;
505 // ReadableStream.prototype.pipeTo SUPPORT
508 * The signature of a function that, when passed an |AbortSignal| instance, will
509 * return the value of its "aborted" flag.
511 * This function will be called while |signal|'s realm has been entered.
513 using AbortSignalIsAborted = bool (*)(JSObject* signal);
516 * Dictate embedder-specific details necessary to implement certain aspects of
517 * the |ReadableStream.prototype.pipeTo| function. This should be performed
518 * exactly once, for a single context associated with a |JSRuntime|.
520 * The |ReadableStream.prototype.pipeTo| function accepts a |signal| argument
521 * that may be used to abort the piping operation. This argument must be either
522 * |undefined| (in other words, the piping operation can't be aborted) or an
523 * |AbortSignal| instance (that may be aborted using the signal's associated
524 * |AbortController|). |AbortSignal| is defined by WebIDL and the DOM in the
525 * web embedding. Therefore, embedders must use this function to specify how
526 * such objects can be recognized and how to perform various essential actions
527 * upon them.
529 * The provided |isAborted| function will be called with an unwrapped
530 * |AbortSignal| instance, while that instance's realm has been entered.
532 * If this function isn't called, and a situation arises where an "is this an
533 * |AbortSignal|?" question must be asked, that question will simply be answered
534 * "no".
536 extern JS_PUBLIC_API void InitPipeToHandling(const JSClass* abortSignalClass,
537 AbortSignalIsAborted isAborted,
538 JSContext* cx);
540 } // namespace JS
542 #endif // js_Stream_h