ladybird/Libraries/LibWeb/Streams/ReadableByteStreamController.h
Shannon Booth 97abc707c7 LibWeb/Bindings: Generate buffer typedefs as variants
Represent BufferSource and ArrayBufferView as ordinary IDL typedefs over
their underlying union types, instead of special casing in the IDL
generator. This allows the union conversion/return machinery handle
these types consistently with other typedefs, which removes buffer
specific paths from the IDL generator.

This necessitates changing the WebIDL::BufferSource and
WebIDL::ArrayBufferView classes as views over these variants. This
replaces the old GC backed BufferableObject wrapper structure and
provide convenience helpers to determine things such as the byte length,
byte offset, backing buffer, and typed-array APIs.
2026-05-30 11:22:08 +02:00

229 lines
10 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Optional.h>
#include <AK/SinglyLinkedList.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Streams/Algorithms.h>
#include <LibWeb/WebIDL/Buffers.h>
namespace Web::Streams {
enum class ReaderType {
Default,
Byob,
None,
};
// https://streams.spec.whatwg.org/#pull-into-descriptor
struct PullIntoDescriptor : public GC::Cell {
GC_CELL(PullIntoDescriptor, GC::Cell);
GC_DECLARE_ALLOCATOR(PullIntoDescriptor);
// https://streams.spec.whatwg.org/#pull-into-descriptor-buffer
// An ArrayBuffer
GC::Ref<JS::ArrayBuffer> buffer;
// https://streams.spec.whatwg.org/#pull-into-descriptor-buffer-byte-length
// A positive integer representing the initial byte length of buffer
u64 buffer_byte_length;
// https://streams.spec.whatwg.org/#pull-into-descriptor-byte-offset
// A nonnegative integer byte offset into the buffer where the underlying byte source will start writing
u64 byte_offset;
// https://streams.spec.whatwg.org/#pull-into-descriptor-byte-length
// A positive integer number of bytes which can be written into the buffer
u64 byte_length;
// https://streams.spec.whatwg.org/#pull-into-descriptor-bytes-filled
// A nonnegative integer number of bytes that have been written into the buffer so far
u64 bytes_filled;
// https://streams.spec.whatwg.org/#pull-into-descriptor-minimum-fill
// A positive integer representing the minimum number of bytes that must be written into the buffer before the associated read() request may be fulfilled. By default, this equals the element size.
u64 minimum_fill;
// https://streams.spec.whatwg.org/#pull-into-descriptor-element-size
// A positive integer representing the number of bytes that can be written into the buffer at a time, using views of the type described by the view constructor
u64 element_size;
// https://streams.spec.whatwg.org/#pull-into-descriptor-view-constructor
// A typed array constructor or %DataView%, which will be used for constructing a view with which to write into the buffer
GC::Ref<JS::NativeFunction> view_constructor;
// https://streams.spec.whatwg.org/#pull-into-descriptor-reader-type
// Either "default" or "byob", indicating what type of readable stream reader initiated this request, or "none" if the initiating reader was released
ReaderType reader_type;
protected:
virtual void visit_edges(Cell::Visitor& visitor) override;
private:
PullIntoDescriptor(
GC::Ref<JS::ArrayBuffer> buffer,
u64 buffer_byte_length,
u64 byte_offset,
u64 byte_length,
u64 bytes_filled,
u64 minimum_fill,
u64 element_size,
GC::Ref<JS::NativeFunction> view_constructor,
ReaderType reader_type)
: buffer(buffer)
, buffer_byte_length(buffer_byte_length)
, byte_offset(byte_offset)
, byte_length(byte_length)
, bytes_filled(bytes_filled)
, minimum_fill(minimum_fill)
, element_size(element_size)
, view_constructor(view_constructor)
, reader_type(reader_type)
{
}
};
// https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry
struct ReadableByteStreamQueueEntry {
// https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry-buffer
// An ArrayBuffer, which will be a transferred version of the one originally supplied by the underlying byte source
GC::Ref<JS::ArrayBuffer> buffer;
// https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry-byte-offset
// A nonnegative integer number giving the byte offset derived from the view originally supplied by the underlying byte source
u64 byte_offset;
// https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry-byte-length
// A nonnegative integer number giving the byte length derived from the view originally supplied by the underlying byte source
u64 byte_length;
};
// https://streams.spec.whatwg.org/#readablebytestreamcontroller
class ReadableByteStreamController : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(ReadableByteStreamController, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(ReadableByteStreamController);
public:
virtual ~ReadableByteStreamController() override = default;
// IDL getter, returns current [[byobRequest]] (if any), and otherwise the [[byobRequest]] for the next pending pull into request
GC::Ptr<ReadableStreamBYOBRequest> byob_request();
void set_byob_request(GC::Ptr<ReadableStreamBYOBRequest> request) { m_byob_request = request; }
// Raw [[byobRequest]] slot
GC::Ptr<ReadableStreamBYOBRequest const> raw_byob_request() const { return m_byob_request; }
GC::Ptr<ReadableStreamBYOBRequest> raw_byob_request() { return m_byob_request; }
Optional<double> desired_size() const;
WebIDL::ExceptionOr<void> close();
void error(Optional<JS::Value> error);
WebIDL::ExceptionOr<void> enqueue(WebIDL::ArrayBufferView);
Optional<u64> const& auto_allocate_chunk_size() { return m_auto_allocate_chunk_size; }
void set_auto_allocate_chunk_size(Optional<u64> value) { m_auto_allocate_chunk_size = value; }
GC::Ptr<CancelAlgorithm> cancel_algorithm() { return m_cancel_algorithm; }
void set_cancel_algorithm(GC::Ptr<CancelAlgorithm> value) { m_cancel_algorithm = value; }
bool close_requested() const { return m_close_requested; }
void set_close_requested(bool value) { m_close_requested = value; }
bool pull_again() const { return m_pull_again; }
void set_pull_again(bool value) { m_pull_again = value; }
GC::Ptr<PullAlgorithm> pull_algorithm() { return m_pull_algorithm; }
void set_pull_algorithm(GC::Ptr<PullAlgorithm> value) { m_pull_algorithm = value; }
bool pulling() const { return m_pulling; }
void set_pulling(bool value) { m_pulling = value; }
SinglyLinkedList<GC::Ref<PullIntoDescriptor>>& pending_pull_intos() { return m_pending_pull_intos; }
SinglyLinkedList<GC::Ref<PullIntoDescriptor>> const& pending_pull_intos() const { return m_pending_pull_intos; }
SinglyLinkedList<ReadableByteStreamQueueEntry>& queue() { return m_queue; }
double queue_total_size() const { return m_queue_total_size; }
void set_queue_total_size(double size) { m_queue_total_size = size; }
bool started() const { return m_started; }
void set_started(bool value) { m_started = value; }
double strategy_hwm() const { return m_strategy_hwm; }
void set_strategy_hwm(double value) { m_strategy_hwm = value; }
GC::Ptr<ReadableStream const> stream() const { return m_stream; }
GC::Ptr<ReadableStream> stream() { return m_stream; }
void set_stream(GC::Ptr<ReadableStream> stream) { m_stream = stream; }
GC::Ref<WebIDL::Promise> cancel_steps(JS::Value reason);
void pull_steps(GC::Ref<ReadRequest>);
void release_steps();
private:
explicit ReadableByteStreamController(JS::Realm&);
virtual void visit_edges(Cell::Visitor&) override;
virtual void initialize(JS::Realm&) override;
// https://streams.spec.whatwg.org/#readablebytestreamcontroller-autoallocatechunksize
// A positive integer, when the automatic buffer allocation feature is enabled. In that case, this value specifies the size of buffer to allocate. It is undefined otherwise.
Optional<u64> m_auto_allocate_chunk_size;
// https://streams.spec.whatwg.org/#readablebytestreamcontroller-byobrequest
// A ReadableStreamBYOBRequest instance representing the current BYOB pull request, or null if there are no pending requests
GC::Ptr<ReadableStreamBYOBRequest> m_byob_request;
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-cancelalgorithm
// A promise-returning algorithm, taking one argument (the cancel reason), which communicates a requested cancelation to the underlying source
GC::Ptr<CancelAlgorithm> m_cancel_algorithm;
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-closerequested
// A boolean flag indicating whether the stream has been closed by its underlying source, but still has chunks in its internal queue that have not yet been read
bool m_close_requested { false };
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-pullagain
// A boolean flag set to true if the streams mechanisms requested a call to the underlying source's pull algorithm to pull more data, but the pull could not yet be done since a previous call is still executing
bool m_pull_again { false };
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-pullalgorithm
// A promise-returning algorithm that pulls data from the underlying source
GC::Ptr<PullAlgorithm> m_pull_algorithm;
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-pulling
// A boolean flag set to true while the underlying source's pull algorithm is executing and the returned promise has not yet fulfilled, used to prevent reentrant calls
bool m_pulling { false };
// https://streams.spec.whatwg.org/#readablebytestreamcontroller-pendingpullintos
// A list of pull-into descriptors
SinglyLinkedList<GC::Ref<PullIntoDescriptor>> m_pending_pull_intos;
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-queue
// A list representing the streams internal queue of chunks
SinglyLinkedList<ReadableByteStreamQueueEntry> m_queue;
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-queuetotalsize
// The total size of all the chunks stored in [[queue]]
double m_queue_total_size { 0 };
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-started
// A boolean flag indicating whether the underlying source has finished starting
bool m_started { false };
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-strategyhwm
// A number supplied to the constructor as part of the streams queuing strategy, indicating the point at which the stream will apply backpressure to its underlying source
double m_strategy_hwm { 0 };
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-stream
// The ReadableStream instance controlled
GC::Ptr<ReadableStream> m_stream;
};
}