WritableStream.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/PromiseCapability.h>
  7. #include <LibWeb/Bindings/Intrinsics.h>
  8. #include <LibWeb/Bindings/WritableStreamPrototype.h>
  9. #include <LibWeb/Streams/AbstractOperations.h>
  10. #include <LibWeb/Streams/UnderlyingSink.h>
  11. #include <LibWeb/Streams/WritableStream.h>
  12. #include <LibWeb/Streams/WritableStreamDefaultController.h>
  13. #include <LibWeb/Streams/WritableStreamDefaultWriter.h>
  14. #include <LibWeb/WebIDL/ExceptionOr.h>
  15. namespace Web::Streams {
  16. // https://streams.spec.whatwg.org/#ws-constructor
  17. WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStream>> WritableStream::construct_impl(JS::Realm& realm, Optional<JS::Handle<JS::Object>> const& underlying_sink_object)
  18. {
  19. auto& vm = realm.vm();
  20. auto writable_stream = MUST_OR_THROW_OOM(realm.heap().allocate<WritableStream>(realm, realm));
  21. // 1. If underlyingSink is missing, set it to null.
  22. auto underlying_sink = underlying_sink_object.has_value() ? JS::Value(underlying_sink_object.value().ptr()) : JS::js_null();
  23. // 2. Let underlyingSinkDict be underlyingSink, converted to an IDL value of type UnderlyingSink.
  24. auto underlying_sink_dict = TRY(UnderlyingSink::from_value(vm, underlying_sink));
  25. // 3. If underlyingSinkDict["type"] exists, throw a RangeError exception.
  26. if (!underlying_sink_dict.type.has_value())
  27. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "Invalid use of reserved key 'type'"sv };
  28. // 4. Perform ! InitializeWritableStream(this).
  29. // Note: This AO configures slot values which are already specified in the class's field initializers.
  30. // FIXME: 5. Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).
  31. SizeAlgorithm size_algorithm = [](auto const&) { return JS::normal_completion(JS::Value(1)); };
  32. // FIXME: 6. Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).
  33. auto high_water_mark = 1.0;
  34. // FIXME: 7. Perform ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm).
  35. (void)high_water_mark;
  36. return writable_stream;
  37. }
  38. // https://streams.spec.whatwg.org/#ws-locked
  39. bool WritableStream::locked() const
  40. {
  41. // 1. Return ! IsWritableStreamLocked(this).
  42. return is_writable_stream_locked(*this);
  43. }
  44. // https://streams.spec.whatwg.org/#ws-close
  45. WebIDL::ExceptionOr<JS::GCPtr<JS::Object>> WritableStream::close()
  46. {
  47. auto& realm = this->realm();
  48. // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
  49. if (is_writable_stream_locked(*this)) {
  50. auto exception = MUST_OR_THROW_OOM(JS::TypeError::create(realm, "Cannot close a locked stream"sv));
  51. return WebIDL::create_rejected_promise(realm, exception)->promise();
  52. }
  53. // 2. If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception.
  54. if (writable_stream_close_queued_or_in_flight(*this)) {
  55. auto exception = MUST_OR_THROW_OOM(JS::TypeError::create(realm, "Cannot close a stream that is already closed or errored"sv));
  56. return WebIDL::create_rejected_promise(realm, exception)->promise();
  57. }
  58. // 3. Return ! WritableStreamClose(this).
  59. return TRY(writable_stream_close(*this))->promise();
  60. }
  61. WritableStream::WritableStream(JS::Realm& realm)
  62. : Bindings::PlatformObject(realm)
  63. {
  64. }
  65. JS::ThrowCompletionOr<void> WritableStream::initialize(JS::Realm& realm)
  66. {
  67. MUST_OR_THROW_OOM(Base::initialize(realm));
  68. set_prototype(&Bindings::ensure_web_prototype<Bindings::WritableStreamPrototype>(realm, "WritableStream"));
  69. return {};
  70. }
  71. void WritableStream::visit_edges(Cell::Visitor& visitor)
  72. {
  73. Base::visit_edges(visitor);
  74. visitor.visit(m_close_request);
  75. visitor.visit(m_controller);
  76. visitor.visit(m_in_flight_write_request);
  77. visitor.visit(m_in_flight_close_request);
  78. if (m_pending_abort_request.has_value()) {
  79. visitor.visit(m_pending_abort_request->promise);
  80. visitor.visit(m_pending_abort_request->reason);
  81. }
  82. visitor.visit(m_stored_error);
  83. visitor.visit(m_writer);
  84. for (auto& write_request : m_write_requests)
  85. visitor.visit(write_request);
  86. }
  87. }