From bdab548b4a9cdf8ef08977a2db2e69a60738ef09 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 19 Dec 2024 19:13:39 -0800 Subject: [PATCH] More files --- src/bun.js/bindings/BunWritableStream.h | 1 + .../BunWritableStreamDefaultController.h | 1 + .../BunWritableStreamDefaultWriter.cpp | 316 +----------------- .../bindings/BunWritableStreamDefaultWriter.h | 8 +- ...WritableStreamDefaultWriterConstructor.cpp | 74 ++++ ...unWritableStreamDefaultWriterConstructor.h | 44 +++ ...unWritableStreamDefaultWriterPrototype.cpp | 188 +++++++++++ .../BunWritableStreamDefaultWriterPrototype.h | 37 ++ 8 files changed, 353 insertions(+), 316 deletions(-) create mode 100644 src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp create mode 100644 src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h create mode 100644 src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp create mode 100644 src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h diff --git a/src/bun.js/bindings/BunWritableStream.h b/src/bun.js/bindings/BunWritableStream.h index 127bd853c6..ac17c37b58 100644 --- a/src/bun.js/bindings/BunWritableStream.h +++ b/src/bun.js/bindings/BunWritableStream.h @@ -33,6 +33,7 @@ public: JSValue error(JSGlobalObject*, JSValue error); JSValue abort(JSGlobalObject*, JSValue reason); JSValue close(JSGlobalObject*); + void write(JSGlobalObject*, JSValue chunk); void finishInFlightClose(); void finishInFlightCloseWithError(JSValue error); diff --git a/src/bun.js/bindings/BunWritableStreamDefaultController.h b/src/bun.js/bindings/BunWritableStreamDefaultController.h index cedd1a7220..7b5d7c6bb6 100644 --- a/src/bun.js/bindings/BunWritableStreamDefaultController.h +++ b/src/bun.js/bindings/BunWritableStreamDefaultController.h @@ -41,6 +41,7 @@ public: // JavaScript-facing methods JSC::JSValue error(JSC::JSGlobalObject* globalObject, JSC::JSValue reason); JSC::JSValue close(JSC::JSGlobalObject* globalObject); + void write(JSC::JSGlobalObject* globalObject, JSC::JSValue chunk); // C++-facing methods bool shouldCallWrite() const; diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp index 83673f1355..6f1b0765eb 100644 --- a/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriter.cpp @@ -1,253 +1,11 @@ -#include "root.h" - #include "BunWritableStreamDefaultWriter.h" #include "BunWritableStream.h" #include "JSDOMWrapper.h" -#include namespace Bun { using namespace JSC; -class JSWritableStreamDefaultWriter; -class JSWritableStreamDefaultWriterPrototype; - -class JSWritableStreamDefaultWriterConstructor final : public JSC::InternalFunction { -public: - using Base = JSC::InternalFunction; - - static JSWritableStreamDefaultWriterConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSWritableStreamDefaultWriterPrototype* prototype); - - DECLARE_INFO; - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForBunClassConstructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBunClassConstructor = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForBunClassConstructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForBunClassConstructor = std::forward(space); }); - } - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); - } - - static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); - static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); - -private: - JSWritableStreamDefaultWriterConstructor(JSC::VM&, JSC::Structure*); - void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSWritableStreamDefaultWriterPrototype*); -}; - -class JSWritableStreamDefaultWriterPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - - static JSWritableStreamDefaultWriterPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) - { - JSWritableStreamDefaultWriterPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultWriterPrototype(vm, structure); - ptr->finishCreation(vm, globalObject); - return ptr; - } - - DECLARE_INFO; - - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriterPrototype, Base); - return &vm.plainObjectSpace(); - } - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - -private: - JSWritableStreamDefaultWriterPrototype(JSC::VM& vm, JSC::Structure* structure) - : Base(vm, structure) - { - } - - void finishCreation(JSC::VM&, JSC::JSGlobalObject*); -}; - -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter); -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter); -static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose); -static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock); - -// Property attributes for standard WritableStreamDefaultWriter prototype properties -static const unsigned ProtoAccessorDontDelete = PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor; -static const unsigned ProtoFunctionDontEnum = PropertyAttribute::DontEnum | PropertyAttribute::Function; - -// Table of prototype properties and methods -static const HashTableValue JSWritableStreamDefaultWriterPrototypeTableValues[] = { - { "closed"_s, ProtoAccessorDontDelete, NoIntrinsic, - { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterClosedGetter, nullptr } }, - { "ready"_s, ProtoAccessorDontDelete, NoIntrinsic, - { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterReadyGetter, nullptr } }, - { "desiredSize"_s, ProtoAccessorDontDelete, NoIntrinsic, - { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterDesiredSizeGetter, nullptr } }, - { "write"_s, ProtoFunctionDontEnum, NoIntrinsic, - { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterWrite, 1 } }, - { "abort"_s, ProtoFunctionDontEnum, NoIntrinsic, - { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterAbort, 1 } }, - { "close"_s, ProtoFunctionDontEnum, NoIntrinsic, - { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterClose, 0 } }, - { "releaseLock"_s, ProtoFunctionDontEnum, NoIntrinsic, - { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterReleaseLock, 0 } }, -}; - -const ClassInfo JSWritableStreamDefaultWriterPrototype::s_info = { - "WritableStreamDefaultWriter"_s, - &Base::s_info, - nullptr, - nullptr, - CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterPrototype) -}; - -void JSWritableStreamDefaultWriterPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - reifyStaticProperties(vm, info(), JSWritableStreamDefaultWriterPrototypeTableValues, *this); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); -} - -// Getter implementations -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - auto* writer = jsDynamicCast(JSValue::decode(thisValue)); - if (!writer) { - throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); - return encodedJSValue(); - } - - return JSValue::encode(writer->closed()); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - auto* writer = jsDynamicCast(JSValue::decode(thisValue)); - if (!writer) { - throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); - return encodedJSValue(); - } - - return JSValue::encode(writer->ready()); -} - -JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - auto* writer = jsDynamicCast(JSValue::decode(thisValue)); - if (!writer) { - throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); - return encodedJSValue(); - } - - return JSValue::encode(jsNumber(writer->desiredSize())); -} - -// Additional JS method implementation -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); - if (!writer) { - scope.throwException(globalObject, createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); - return {}; - } - - writer->release(); - return JSValue::encode(jsUndefined()); -} - -const ClassInfo JSWritableStreamDefaultWriterConstructor::s_info = { - "Function"_s, - &Base::s_info, - nullptr, - nullptr, - CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterConstructor) -}; - -JSWritableStreamDefaultWriterConstructor::JSWritableStreamDefaultWriterConstructor(VM& vm, Structure* structure) - : Base(vm, structure, call, construct) -{ -} - -void JSWritableStreamDefaultWriterConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSWritableStreamDefaultWriterPrototype* prototype) -{ - Base::finishCreation(vm, 1, "WritableStreamDefaultWriter"_s, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - ASSERT(inherits(info())); -} - -JSWritableStreamDefaultWriterConstructor* JSWritableStreamDefaultWriterConstructor::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSWritableStreamDefaultWriterPrototype* prototype) -{ - JSWritableStreamDefaultWriterConstructor* constructor = new (NotNull, allocateCell(vm)) JSWritableStreamDefaultWriterConstructor(vm, structure); - constructor->finishCreation(vm, globalObject, prototype); - return constructor; -} - -// This is called when constructing a new writer with new WritableStreamDefaultWriter(stream) -EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) -{ - VM& vm = lexicalGlobalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - if (!callFrame->argumentCount()) { - throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor requires a WritableStream argument"_s); - return encodedJSValue(); - } - - JSValue streamValue = callFrame->argument(0); - JSWritableStream* stream = jsDynamicCast(streamValue); - if (!stream) { - throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor argument must be a WritableStream"_s); - return encodedJSValue(); - } - - // Check if stream is locked - if (stream->isLocked()) { - throwTypeError(lexicalGlobalObject, scope, "Cannot construct a WritableStreamDefaultWriter for a locked WritableStream"_s); - return encodedJSValue(); - } - - Structure* structure = globalObject->WritableStreamDefaultWriterStructure(); - JSWritableStreamDefaultWriter* writer = JSWritableStreamDefaultWriter::create(vm, structure, stream); - return JSValue::encode(writer); -} - -// This handles direct calls to WritableStreamDefaultWriter as a function, which should throw an error -EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::call(JSGlobalObject* globalObject, CallFrame*) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - return throwVMTypeError(globalObject, scope, "WritableStreamDefaultWriter constructor cannot be called as a function"_s); -} - const ClassInfo JSWritableStreamDefaultWriter::s_info = { "WritableStreamDefaultWriter"_s, &Base::s_info, @@ -259,8 +17,6 @@ const ClassInfo JSWritableStreamDefaultWriter::s_info = { JSWritableStreamDefaultWriter::JSWritableStreamDefaultWriter(VM& vm, Structure* structure, JSWritableStream* stream) : Base(vm, structure) , m_stream(vm, this, stream) - , m_closedPromise(vm, this, JSPromise::create(vm, globalObject->promiseStructure())) - , m_readyPromise(vm, this, JSPromise::create(vm, globalObject->promiseStructure())) { } @@ -298,79 +54,11 @@ void JSWritableStreamDefaultWriter::visitAdditionalChildren(Visitor& visitor) visitor.append(m_stream); visitor.append(m_closedPromise); visitor.append(m_readyPromise); + visitor.append(m_writeRequests); } DEFINE_VISIT_ADDITIONAL_CHILDREN(JSWritableStreamDefaultWriter); -// JS Interface Methods - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); - if (!writer) { - scope.throwException(globalObject, - createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); - return {}; - } - - JSValue chunk = callFrame->argument(0); - - JSValue error; - if (!writer->write(globalObject, chunk, &error)) { - scope.throwException(globalObject, error); - return {}; - } - - return JSValue::encode(jsUndefined()); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); - if (!writer) { - scope.throwException(globalObject, - createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); - return {}; - } - - JSValue error; - if (!writer->close(globalObject, &error)) { - scope.throwException(globalObject, error); - return {}; - } - - return JSValue::encode(jsUndefined()); -} - -JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort, (JSGlobalObject * globalObject, CallFrame* callFrame)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - - JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); - if (!writer) { - scope.throwException(globalObject, - createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); - return {}; - } - - JSValue reason = callFrame->argument(0); - - JSValue error; - if (!writer->abort(globalObject, reason, &error)) { - scope.throwException(globalObject, error); - return {}; - } - - return JSValue::encode(jsUndefined()); -} - // Non-JS Methods for C++ Use bool JSWritableStreamDefaultWriter::write(JSGlobalObject* globalObject, JSValue chunk, JSValue* error) @@ -383,7 +71,7 @@ bool JSWritableStreamDefaultWriter::write(JSGlobalObject* globalObject, JSValue return false; } - return m_stream->write(globalObject, chunk, error); + return m_stream->controller()->write(globalObject, chunk, error); } bool JSWritableStreamDefaultWriter::close(JSGlobalObject* globalObject, JSValue* error) diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriter.h b/src/bun.js/bindings/BunWritableStreamDefaultWriter.h index d47697a474..9cbc7fe9b0 100644 --- a/src/bun.js/bindings/BunWritableStreamDefaultWriter.h +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriter.h @@ -15,10 +15,14 @@ public: using Base = JSC::JSNonFinalObject; static JSWritableStreamDefaultWriter* create(JSC::VM&, JSC::Structure*, JSWritableStream*); - static JSWritableStreamDefaultWriter* createForSubclass(JSC::VM&, JSC::Structure*, JSWritableStream*); template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriter, Base); + return &vm.plainObjectSpace(); + } + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) { return JSC::Structure::create(vm, globalObject, prototype, diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp new file mode 100644 index 0000000000..d48521cc71 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.cpp @@ -0,0 +1,74 @@ +#include "BunWritableStreamDefaultWriterConstructor.h" +#include "BunWritableStreamDefaultWriterPrototype.h" +#include "BunWritableStreamDefaultWriter.h" +#include "BunWritableStream.h" + +namespace Bun { + +using namespace JSC; + +const ClassInfo JSWritableStreamDefaultWriterConstructor::s_info = { + "Function"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterConstructor) +}; + +JSWritableStreamDefaultWriterConstructor::JSWritableStreamDefaultWriterConstructor(VM& vm, Structure* structure) + : Base(vm, structure, call, construct) +{ +} + +void JSWritableStreamDefaultWriterConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSWritableStreamDefaultWriterPrototype* prototype) +{ + Base::finishCreation(vm, 1, "WritableStreamDefaultWriter"_s, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + ASSERT(inherits(info())); +} + +JSWritableStreamDefaultWriterConstructor* JSWritableStreamDefaultWriterConstructor::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSWritableStreamDefaultWriterPrototype* prototype) +{ + JSWritableStreamDefaultWriterConstructor* constructor = new (NotNull, allocateCell(vm)) JSWritableStreamDefaultWriterConstructor(vm, structure); + constructor->finishCreation(vm, globalObject, prototype); + return constructor; +} + +// This is called when constructing a new writer with new WritableStreamDefaultWriter(stream) +EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) +{ + VM& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!callFrame->argumentCount()) { + throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor requires a WritableStream argument"_s); + return encodedJSValue(); + } + + JSValue streamValue = callFrame->argument(0); + JSWritableStream* stream = jsDynamicCast(streamValue); + if (!stream) { + throwTypeError(lexicalGlobalObject, scope, "WritableStreamDefaultWriter constructor argument must be a WritableStream"_s); + return encodedJSValue(); + } + + // Check if stream is locked + if (stream->isLocked()) { + throwTypeError(lexicalGlobalObject, scope, "Cannot construct a WritableStreamDefaultWriter for a locked WritableStream"_s); + return encodedJSValue(); + } + + Structure* structure = globalObject->WritableStreamDefaultWriterStructure(); + JSWritableStreamDefaultWriter* writer = JSWritableStreamDefaultWriter::create(vm, structure, stream); + return JSValue::encode(writer); +} + +// This handles direct calls to WritableStreamDefaultWriter as a function, which should throw an error +EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWritableStreamDefaultWriterConstructor::call(JSGlobalObject* globalObject, CallFrame*) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(globalObject, scope, "WritableStreamDefaultWriter constructor cannot be called as a function"_s); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h new file mode 100644 index 0000000000..ed4120d0ab --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterConstructor.h @@ -0,0 +1,44 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +class JSWritableStreamDefaultWriterPrototype; + +class JSWritableStreamDefaultWriterConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSWritableStreamDefaultWriterConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSWritableStreamDefaultWriterPrototype* prototype); + + DECLARE_INFO; + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForBunClassConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBunClassConstructor = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForBunClassConstructor.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForBunClassConstructor = std::forward(space); }); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); + } + +private: + JSWritableStreamDefaultWriterConstructor(JSC::VM&, JSC::Structure*); + void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSWritableStreamDefaultWriterPrototype*); + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*); + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*); +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp new file mode 100644 index 0000000000..89d45efad6 --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.cpp @@ -0,0 +1,188 @@ +#include "BunWritableStreamDefaultWriterPrototype.h" +#include "BunWritableStreamDefaultWriter.h" +#include "JSDOMWrapper.h" + +namespace Bun { + +using namespace JSC; + +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter); +static JSC_DECLARE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose); +static JSC_DECLARE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock); + +// Property attributes for standard WritableStreamDefaultWriter prototype properties +static const unsigned ProtoAccessorDontDelete = PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor; +static const unsigned ProtoFunctionDontEnum = PropertyAttribute::DontEnum | PropertyAttribute::Function; + +// Table of prototype properties and methods +static const HashTableValue JSWritableStreamDefaultWriterPrototypeTableValues[] = { + { "closed"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterClosedGetter, nullptr } }, + { "ready"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterReadyGetter, nullptr } }, + { "desiredSize"_s, ProtoAccessorDontDelete, NoIntrinsic, + { HashTableValue::GetterSetterType, jsWritableStreamDefaultWriterDesiredSizeGetter, nullptr } }, + { "write"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterWrite, 1 } }, + { "abort"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterAbort, 1 } }, + { "close"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterClose, 0 } }, + { "releaseLock"_s, ProtoFunctionDontEnum, NoIntrinsic, + { HashTableValue::NativeFunctionType, jsWritableStreamDefaultWriterReleaseLock, 0 } }, +}; + +const ClassInfo JSWritableStreamDefaultWriterPrototype::s_info = { + "WritableStreamDefaultWriter"_s, + &Base::s_info, + nullptr, + nullptr, + CREATE_METHOD_TABLE(JSWritableStreamDefaultWriterPrototype) +}; + +JSWritableStreamDefaultWriterPrototype* JSWritableStreamDefaultWriterPrototype::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) +{ + JSWritableStreamDefaultWriterPrototype* ptr = new (NotNull, JSC::allocateCell(vm)) JSWritableStreamDefaultWriterPrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; +} + +void JSWritableStreamDefaultWriterPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + reifyStaticProperties(vm, info(), JSWritableStreamDefaultWriterPrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +// Getter implementations +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterClosedGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(writer->closed()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterReadyGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(writer->ready()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsWritableStreamDefaultWriterDesiredSizeGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* writer = jsDynamicCast(JSValue::decode(thisValue)); + if (!writer) { + throwTypeError(globalObject, scope, "Not a WritableStreamDefaultWriter"_s); + return encodedJSValue(); + } + + return JSValue::encode(jsNumber(writer->desiredSize())); +} + +// Method implementations +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterWrite, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + JSValue chunk = callFrame->argument(0); + + JSValue error; + if (!writer->write(globalObject, chunk, &error)) { + scope.throwException(globalObject, error); + return {}; + } + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterClose, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + JSValue error; + if (!writer->close(globalObject, &error)) { + scope.throwException(globalObject, error); + return {}; + } + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterAbort, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + JSValue reason = callFrame->argument(0); + + JSValue error; + if (!writer->abort(globalObject, reason, &error)) { + scope.throwException(globalObject, error); + return {}; + } + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsWritableStreamDefaultWriterReleaseLock, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSWritableStreamDefaultWriter* writer = jsDynamicCast(callFrame->thisValue()); + if (!writer) { + scope.throwException(globalObject, + createTypeError(globalObject, "Not a WritableStreamDefaultWriter"_s)); + return {}; + } + + writer->release(); + return JSValue::encode(jsUndefined()); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h new file mode 100644 index 0000000000..2e6c074b0c --- /dev/null +++ b/src/bun.js/bindings/BunWritableStreamDefaultWriterPrototype.h @@ -0,0 +1,37 @@ +#pragma once + +#include "root.h" +#include + +namespace Bun { + +class JSWritableStreamDefaultWriterPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSWritableStreamDefaultWriterPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSWritableStreamDefaultWriterPrototype, Base); + return &vm.plainObjectSpace(); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + +private: + JSWritableStreamDefaultWriterPrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +} // namespace Bun