LibWeb/Streams: Move ReadableStream functions out of AbstractOperations

These are not defined in the abstract operations section of the spec and
are the publically exported Stream APIs exposed on ReadableStream.
This commit is contained in:
Shannon Booth 2024-12-08 17:28:44 +13:00 committed by Jelle Raaijmakers
parent c6d0f87bb7
commit 3f572d9ab7
Notes: github-actions[bot] 2024-12-11 14:12:43 +00:00
8 changed files with 136 additions and 131 deletions

View file

@ -7,6 +7,7 @@
*/
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/ReadableStreamPrototype.h>
#include <LibWeb/DOM/AbortSignal.h>
@ -258,4 +259,128 @@ bool ReadableStream::is_disturbed() const
return m_disturbed;
}
// https://streams.spec.whatwg.org/#readablestream-pull-from-bytes
WebIDL::ExceptionOr<void> ReadableStream::pull_from_bytes(ByteBuffer bytes)
{
auto& realm = this->realm();
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
auto& controller = this->controller()->get<GC::Ref<ReadableByteStreamController>>();
// 2. Let available be bytess length.
auto available = bytes.size();
// 3. Let desiredSize be available.
auto desired_size = available;
// FIXME: 4. If streams current BYOB request view is non-null, then set desiredSize to streams current BYOB request
// view's byte length.
// 5. Let pullSize be the smaller value of available and desiredSize.
auto pull_size = min(available, desired_size);
// 6. Let pulled be the first pullSize bytes of bytes.
auto pulled = pull_size == available ? move(bytes) : MUST(bytes.slice(0, pull_size));
// 7. Remove the first pullSize bytes from bytes.
if (pull_size != available)
bytes = MUST(bytes.slice(pull_size, available - pull_size));
// FIXME: 8. If streams current BYOB request view is non-null, then:
// 1. Write pulled into streams current BYOB request view.
// 2. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], pullSize).
// 9. Otherwise,
{
// 1. Set view to the result of creating a Uint8Array from pulled in streams relevant Realm.
auto array_buffer = JS::ArrayBuffer::create(realm, move(pulled));
auto view = JS::Uint8Array::create(realm, array_buffer->byte_length(), *array_buffer);
// 2. Perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], view).
TRY(readable_byte_stream_controller_enqueue(controller, view));
}
return {};
}
// https://streams.spec.whatwg.org/#readablestream-enqueue
WebIDL::ExceptionOr<void> ReadableStream::enqueue(JS::Value chunk)
{
VERIFY(m_controller.has_value());
// 1. If stream.[[controller]] implements ReadableStreamDefaultController,
if (m_controller->has<GC::Ref<ReadableStreamDefaultController>>()) {
// 1. Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
return readable_stream_default_controller_enqueue(m_controller->get<GC::Ref<ReadableStreamDefaultController>>(), chunk);
}
// 2. Otherwise,
else {
// 1. Assert: stream.[[controller]] implements ReadableByteStreamController.
VERIFY(m_controller->has<GC::Ref<ReadableByteStreamController>>());
auto readable_byte_controller = m_controller->get<GC::Ref<ReadableByteStreamController>>();
// FIXME: 2. Assert: chunk is an ArrayBufferView.
// 3. Let byobView be the current BYOB request view for stream.
// FIXME: This is not what the spec means by 'current BYOB request view'
auto byob_view = readable_byte_controller->raw_byob_request();
// 4. If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is byobView.[[ViewedArrayBuffer]], then:
if (byob_view) {
// FIXME: 1. Assert: chunk.[[ByteOffset]] is byobView.[[ByteOffset]].
// FIXME: 2. Assert: chunk.[[ByteLength]] ≤ byobView.[[ByteLength]].
// FIXME: 3. Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], chunk.[[ByteLength]]).
TODO();
}
// 5. Otherwise, perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], chunk).
return readable_byte_stream_controller_enqueue(readable_byte_controller, chunk);
}
}
// https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support
void ReadableStream::set_up_with_byte_reading_support(GC::Ptr<PullAlgorithm> pull_algorithm, GC::Ptr<CancelAlgorithm> cancel_algorithm, double high_water_mark)
{
auto& realm = this->realm();
// 1. Let startAlgorithm be an algorithm that returns undefined.
auto start_algorithm = GC::create_function(realm.heap(), []() -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); });
// 2. Let pullAlgorithmWrapper be an algorithm that runs these steps:
auto pull_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, pull_algorithm]() {
// 1. Let result be the result of running pullAlgorithm, if pullAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
GC::Ptr<JS::PromiseCapability> result = nullptr;
if (pull_algorithm)
result = pull_algorithm->function()();
// 2. If result is a Promise, then return result.
if (result != nullptr)
return GC::Ref(*result);
// 3. Return a promise resolved with undefined.
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});
// 3. Let cancelAlgorithmWrapper be an algorithm that runs these steps:
auto cancel_algorithm_wrapper = GC::create_function(realm.heap(), [&realm, cancel_algorithm](JS::Value c) {
// 1. Let result be the result of running cancelAlgorithm, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
GC::Ptr<JS::PromiseCapability> result = nullptr;
if (cancel_algorithm)
result = cancel_algorithm->function()(c);
// 2. If result is a Promise, then return result.
if (result != nullptr)
return GC::Ref(*result);
// 3. Return a promise resolved with undefined.
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});
// 4. Perform ! InitializeReadableStream(stream).
// 5. Let controller be a new ReadableByteStreamController.
auto controller = realm.create<ReadableByteStreamController>(realm);
// 6. Perform ! SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper, highWaterMark, undefined).
MUST(set_up_readable_byte_stream_controller(*this, controller, start_algorithm, pull_algorithm_wrapper, cancel_algorithm_wrapper, high_water_mark, JS::js_undefined()));
}
}