DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
/* -*- 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