summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2023-03-28 17:43:34 -0700
committerLinus Groh <mail@linusgroh.de>2023-04-01 23:43:07 +0100
commitfe69d66a4ee81ed9b78d82631406329378f842bf (patch)
treee6d7d17f785eca2c0736459753f11bc0304dd931 /Userland/Libraries
parentf409f68a9aaa51f0e1b6a157e73c6edb16e3de24 (diff)
downloadserenity-fe69d66a4ee81ed9b78d82631406329378f842bf.zip
LibWeb: Add the ReadableStreamGenericReader mixin interface
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibWeb/Forward.h1
-rw-r--r--Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp81
-rw-r--r--Userland/Libraries/LibWeb/Streams/AbstractOperations.h8
-rw-r--r--Userland/Libraries/LibWeb/Streams/ReadableStream.cpp1
-rw-r--r--Userland/Libraries/LibWeb/Streams/ReadableStream.h7
-rw-r--r--Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp45
-rw-r--r--Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h42
-rw-r--r--Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.idl6
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);
+};