ladybird/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp
Linus Groh 742f6f7e26 LibWeb/Streams: Fix inconsistent uses of realm() and vm()
This is not documented yet, but the preferred style is getting both
upfront instead of inlining various kinds of calls in places that use
the realm and vm.
2023-04-13 09:51:48 +02:00

149 lines
5.4 KiB
C++

/*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Streams/AbstractOperations.h>
#include <LibWeb/Streams/ReadableStream.h>
#include <LibWeb/Streams/ReadableStreamDefaultController.h>
#include <LibWeb/Streams/ReadableStreamDefaultReader.h>
#include <LibWeb/Streams/UnderlyingSource.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::Streams {
// https://streams.spec.whatwg.org/#rs-constructor
WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> ReadableStream::construct_impl(JS::Realm& realm, Optional<JS::Handle<JS::Object>> const& underlying_source_object)
{
auto& vm = realm.vm();
auto readable_stream = MUST_OR_THROW_OOM(realm.heap().allocate<ReadableStream>(realm, realm));
// 1. If underlyingSource is missing, set it to null.
auto underlying_source = underlying_source_object.has_value() ? JS::Value(underlying_source_object.value().ptr()) : JS::js_null();
// 2. Let underlyingSourceDict be underlyingSource, converted to an IDL value of type UnderlyingSource.
auto underlying_source_dict = TRY(UnderlyingSource::from_value(vm, underlying_source));
// 3. Perform ! InitializeReadableStream(this).
// 4. If underlyingSourceDict["type"] is "bytes":
if (underlying_source_dict.type.has_value() && underlying_source_dict.type.value() == ReadableStreamType::Bytes) {
// FIXME:
// 1. If strategy["size"] exists, throw a RangeError exception.
// 2. Let highWaterMark be ? ExtractHighWaterMark(strategy, 0).
// 3. Perform ? SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark).
TODO();
}
// 5. Otherwise,
else {
// 1. Assert: underlyingSourceDict["type"] does not exist.
VERIFY(!underlying_source_dict.type.has_value());
// FIXME: 2. Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).
SizeAlgorithm size_algorithm = [](auto const&) { return JS::normal_completion(JS::Value(1)); };
// FIXME: 3. Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).
auto high_water_mark = 1.0;
// 4. Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark, sizeAlgorithm).
TRY(set_up_readable_stream_default_controller_from_underlying_source(*readable_stream, underlying_source, underlying_source_dict, high_water_mark, move(size_algorithm)));
}
return readable_stream;
}
ReadableStream::ReadableStream(JS::Realm& realm)
: PlatformObject(realm)
{
}
ReadableStream::~ReadableStream() = default;
// https://streams.spec.whatwg.org/#rs-locked
bool ReadableStream::locked()
{
// 1. Return ! IsReadableStreamLocked(this).
return is_readable_stream_locked(*this);
}
// https://streams.spec.whatwg.org/#rs-cancel
WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> ReadableStream::cancel(JS::Value reason)
{
auto& realm = this->realm();
// 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_readable_stream_locked(*this)) {
auto exception = MUST_OR_THROW_OOM(JS::TypeError::create(realm, "Cannot cancel a locked stream"sv));
return WebIDL::create_rejected_promise(realm, JS::Value { exception })->promise();
}
// 2. Return ! ReadableStreamCancel(this, reason).
return TRY(readable_stream_cancel(*this, reason))->promise();
}
// https://streams.spec.whatwg.org/#rs-get-reader
WebIDL::ExceptionOr<ReadableStreamReader> ReadableStream::get_reader()
{
// FIXME:
// 1. If options["mode"] does not exist, return ? AcquireReadableStreamDefaultReader(this).
// 2. Assert: options["mode"] is "byob".
// 3. Return ? AcquireReadableStreamBYOBReader(this).
return TRY(acquire_readable_stream_default_reader(*this));
}
JS::ThrowCompletionOr<void> ReadableStream::initialize(JS::Realm& realm)
{
MUST_OR_THROW_OOM(Base::initialize(realm));
set_prototype(&Bindings::ensure_web_prototype<Bindings::ReadableStreamPrototype>(realm, "ReadableStream"));
return {};
}
void ReadableStream::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_controller);
visitor.visit(m_stored_error);
visitor.visit(m_reader);
}
// https://streams.spec.whatwg.org/#readablestream-locked
bool ReadableStream::is_readable() const
{
// A ReadableStream stream is readable if stream.[[state]] is "readable".
return m_state == State::Readable;
}
// https://streams.spec.whatwg.org/#readablestream-closed
bool ReadableStream::is_closed() const
{
// A ReadableStream stream is closed if stream.[[state]] is "closed".
return m_state == State::Closed;
}
// https://streams.spec.whatwg.org/#readablestream-errored
bool ReadableStream::is_errored() const
{
// A ReadableStream stream is errored if stream.[[state]] is "errored".
return m_state == State::Errored;
}
// https://streams.spec.whatwg.org/#readablestream-locked
bool ReadableStream::is_locked() const
{
// A ReadableStream stream is locked if ! IsReadableStreamLocked(stream) returns true.
return is_readable_stream_locked(*this);
}
// https://streams.spec.whatwg.org/#is-readable-stream-disturbed
bool ReadableStream::is_disturbed() const
{
// A ReadableStream stream is disturbed if stream.[[disturbed]] is true.
return m_disturbed;
}
}