1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:37:46 +00:00

LibWeb: Add the ReadableStreamGenericReader mixin interface

This commit is contained in:
Matthew Olsson 2023-03-28 17:43:34 -07:00 committed by Linus Groh
parent f409f68a9a
commit fe69d66a4e
9 changed files with 189 additions and 3 deletions

View file

@ -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

View file

@ -418,6 +418,7 @@ class Selection;
namespace Web::Streams {
class ReadableStream;
class ReadableStreamGenericReaderMixin;
}
namespace Web::SVG {

View file

@ -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 readIntoRequests 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 readRequests 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));
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 streams current state, used internally; one of "readable", "closed", or "errored"

View file

@ -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);
}
}

View file

@ -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;
};
}

View file

@ -0,0 +1,6 @@
// https://streams.spec.whatwg.org/#readablestreamgenericreader
interface mixin ReadableStreamGenericReader {
readonly attribute Promise<undefined> closed;
Promise<undefined> cancel(optional any reason);
};