diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2023-03-28 17:43:34 -0700 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-04-01 23:43:07 +0100 |
commit | fe69d66a4ee81ed9b78d82631406329378f842bf (patch) | |
tree | e6d7d17f785eca2c0736459753f11bc0304dd931 /Userland/Libraries | |
parent | f409f68a9aaa51f0e1b6a157e73c6edb16e3de24 (diff) | |
download | serenity-fe69d66a4ee81ed9b78d82631406329378f842bf.zip |
LibWeb: Add the ReadableStreamGenericReader mixin interface
Diffstat (limited to 'Userland/Libraries')
9 files changed, 189 insertions, 3 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 761469ac09..8f9909a8d6 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -456,6 +456,7 @@ set(SOURCES SecureContexts/AbstractOperations.cpp Streams/AbstractOperations.cpp Streams/ReadableStream.cpp + Streams/ReadableStreamGenericReader.cpp SVG/AttributeNames.cpp SVG/AttributeParser.cpp SVG/SVGAnimatedLength.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 2d3f1a9ad7..143fa04a5e 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -418,6 +418,7 @@ class Selection; namespace Web::Streams { class ReadableStream; +class ReadableStreamGenericReaderMixin; } namespace Web::SVG { diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp index ac1045b707..3f12814e09 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -1,11 +1,14 @@ /* * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ #include <LibWeb/Streams/AbstractOperations.h> #include <LibWeb/Streams/ReadableStream.h> +#include <LibWeb/Streams/ReadableStreamGenericReader.h> +#include <LibWeb/WebIDL/ExceptionOr.h> namespace Web::Streams { @@ -20,4 +23,82 @@ bool is_readable_stream_locked(ReadableStream const& stream) return true; } +// https://streams.spec.whatwg.org/#readable-stream-cancel +WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> readable_stream_cancel(ReadableStream& stream, JS::Value reason) +{ + auto& realm = stream.realm(); + + // 1. Set stream.[[disturbed]] to true. + stream.set_disturbed(true); + + // 2. If stream.[[state]] is "closed", return a promise resolved with undefined. + if (stream.is_closed()) + return WebIDL::create_resolved_promise(realm, JS::js_undefined()); + + // 3. If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]]. + if (stream.is_errored()) + return WebIDL::create_rejected_promise(realm, stream.stored_error()); + + // 4. Perform ! ReadableStreamClose(stream). + readable_stream_close(stream); + + // 5. Let reader be stream.[[reader]]. + auto reader = stream.reader(); + + // FIXME: + // 6. If reader is not undefined and reader implements ReadableStreamBYOBReader, + // 1. Let readIntoRequests be reader.[[readIntoRequests]]. + // 2. Set reader.[[readIntoRequests]] to an empty list. + // 3. For each readIntoRequest of readIntoRequests, + // 1. Perform readIntoRequest’s close steps, given undefined. + // 7. Let sourceCancelPromise be ! stream.[[controller]].[[CancelSteps]](reason). + // 8. Return the result of reacting to sourceCancelPromise with a fulfillment step that returns undefined. + (void)reader; + (void)reason; + + return WebIDL::create_resolved_promise(realm, JS::js_undefined()); +} + +// https://streams.spec.whatwg.org/#readable-stream-close +void readable_stream_close(ReadableStream& stream) +{ + auto& realm = stream.realm(); + + // 1. Assert: stream.[[state]] is "readable". + VERIFY(stream.is_readable()); + + // 2. Set stream.[[state]] to "closed". + stream.set_stream_state(ReadableStream::State::Closed); + + // 3. Let reader be stream.[[reader]]. + auto reader = stream.reader(); + + // 4. If reader is undefined, return. + if (!reader) + return; + + // 5. Resolve reader.[[closedPromise]] with undefined. + WebIDL::resolve_promise(realm, *reader->closed_promise_capability()); + + // FIXME: + // 6. If reader implements ReadableStreamDefaultReader, + // 1. Let readRequests be reader.[[readRequests]]. + // 2. Set reader.[[readRequests]] to an empty list. + // 3. For each readRequest of readRequests, + // 1. Perform readRequest’s close steps. +} + +// https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel +JS::NonnullGCPtr<WebIDL::Promise> readable_stream_reader_generic_cancel(ReadableStreamGenericReaderMixin& reader, JS::Value reason) +{ + // 1. Let stream be reader.[[stream]] + auto stream = reader.stream(); + + // 2. Assert: stream is not undefined + VERIFY(stream); + + // 3. Return ! ReadableStreamCancel(stream, reason) + return MUST(readable_stream_cancel(*stream, reason)); +} + } diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h index 0ffb117183..867d7e8a70 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h @@ -1,15 +1,23 @@ /* * Copyright (c) 2022, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include <LibJS/Heap/GCPtr.h> #include <LibWeb/Forward.h> +#include <LibWeb/WebIDL/Promise.h> namespace Web::Streams { bool is_readable_stream_locked(ReadableStream const&); +void readable_stream_close(ReadableStream&); +WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> readable_stream_cancel(ReadableStream&, JS::Value reason); + +JS::NonnullGCPtr<WebIDL::Promise> readable_stream_reader_generic_cancel(ReadableStreamGenericReaderMixin&, JS::Value reason); + } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp index 0b905d4280..e931193f3a 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp @@ -36,7 +36,6 @@ void ReadableStream::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_controller); - visitor.visit(m_reader); visitor.visit(m_stored_error); } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.h b/Userland/Libraries/LibWeb/Streams/ReadableStream.h index b0d351d93c..cb24384335 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.h @@ -29,7 +29,7 @@ public: virtual ~ReadableStream() override; JS::GCPtr<JS::Object> controller() const { return m_controller; } - JS::GCPtr<JS::Object> reader() const { return m_reader; } + ReadableStreamGenericReaderMixin* reader() const { return m_reader; } JS::Value stored_error() const { return m_stored_error; } bool is_readable() const; @@ -38,6 +38,9 @@ public: bool is_locked() const; bool is_disturbed() const; + void set_disturbed(bool value) { m_disturbed = value; } + void set_stream_state(State value) { m_state = value; } + private: explicit ReadableStream(JS::Realm&); @@ -58,7 +61,7 @@ private: // https://streams.spec.whatwg.org/#readablestream-reader // A ReadableStreamDefaultReader or ReadableStreamBYOBReader instance, if the stream is locked to a reader, or undefined if it is not - JS::GCPtr<JS::Object> m_reader; + ReadableStreamGenericReaderMixin* m_reader; // https://streams.spec.whatwg.org/#readablestream-state // A string containing the stream’s current state, used internally; one of "readable", "closed", or "errored" diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp new file mode 100644 index 0000000000..e78d71b7de --- /dev/null +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Runtime/Promise.h> +#include <LibJS/Runtime/PromiseCapability.h> +#include <LibWeb/Streams/AbstractOperations.h> +#include <LibWeb/Streams/ReadableStream.h> +#include <LibWeb/Streams/ReadableStreamGenericReader.h> +#include <LibWeb/WebIDL/ExceptionOr.h> +#include <LibWeb/WebIDL/Promise.h> + +namespace Web::Streams { + +// https://streams.spec.whatwg.org/#generic-reader-closed +WebIDL::ExceptionOr<JS::GCPtr<JS::Promise>> ReadableStreamGenericReaderMixin::closed() +{ + // 1. Return this.[[closedPromise]]. + return JS::GCPtr { verify_cast<JS::Promise>(*m_closed_promise->promise()) }; +} + +// https://streams.spec.whatwg.org/#generic-reader-cancel +WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ReadableStreamGenericReaderMixin::cancel(JS::Value reason) +{ + // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. + if (!m_stream) { + auto& realm = stream()->realm(); + auto promise_capability = WebIDL::create_rejected_promise(realm, TRY(JS::TypeError::create(realm, "No stream present to cancel"sv))); + return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) }; + } + + // 2. Return ! ReadableStreamReaderGenericCancel(this, reason). + auto promise_capability = readable_stream_reader_generic_cancel(*this, reason); + return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) }; +} + +void ReadableStreamGenericReaderMixin::visit_edges(JS::Cell::Visitor& visitor) +{ + visitor.visit(m_closed_promise); + visitor.visit(m_stream); +} + +} diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h new file mode 100644 index 0000000000..3bec0d62f3 --- /dev/null +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Forward.h> +#include <LibJS/Forward.h> +#include <LibWeb/Bindings/PlatformObject.h> +#include <LibWeb/Forward.h> +#include <LibWeb/WebIDL/Promise.h> + +namespace Web::Streams { + +// https://streams.spec.whatwg.org/#readablestreamgenericreader +class ReadableStreamGenericReaderMixin { +public: + WebIDL::ExceptionOr<JS::GCPtr<JS::Promise>> closed(); + + WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> cancel(JS::Value reason); + + JS::GCPtr<ReadableStream> stream() const { return m_stream; } + void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; } + + JS::GCPtr<WebIDL::Promise> closed_promise_capability() { return m_closed_promise; } + void set_closed_promise_capability(JS::GCPtr<WebIDL::Promise> promise) { m_closed_promise = promise; } + +protected: + void visit_edges(JS::Cell::Visitor&); + + // https://streams.spec.whatwg.org/#readablestreamgenericreader-closedpromise + // A promise returned by the reader's closed getter + JS::GCPtr<WebIDL::Promise> m_closed_promise; + + // https://streams.spec.whatwg.org/#readablestreamgenericreader-stream + // A ReadableStream instance that owns this reader + JS::GCPtr<ReadableStream> m_stream; +}; + +} diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.idl b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.idl new file mode 100644 index 0000000000..56ce22c9a0 --- /dev/null +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.idl @@ -0,0 +1,6 @@ +// https://streams.spec.whatwg.org/#readablestreamgenericreader +interface mixin ReadableStreamGenericReader { + readonly attribute Promise<undefined> closed; + + Promise<undefined> cancel(optional any reason); +}; |