diff options
Diffstat (limited to 'src/bun.js/bindings/JSReadableState.cpp')
-rw-r--r-- | src/bun.js/bindings/JSReadableState.cpp | 210 |
1 files changed, 125 insertions, 85 deletions
diff --git a/src/bun.js/bindings/JSReadableState.cpp b/src/bun.js/bindings/JSReadableState.cpp index fe19449ff..bf1bc1155 100644 --- a/src/bun.js/bindings/JSReadableState.cpp +++ b/src/bun.js/bindings/JSReadableState.cpp @@ -14,8 +14,6 @@ namespace WebCore { using namespace JSC; static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_pipesCount); -static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_paused); -static JSC_DECLARE_CUSTOM_GETTER(setJSReadableState_paused); int64_t getHighWaterMark(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options) { @@ -52,79 +50,31 @@ void JSReadableState::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObj } putDirect(vm, WTFMove(objectModeIdent), JSC::jsBoolean(objectMode)); - int64_t highWaterMark = objectMode ? 16 : 16 * 1024; // default value + m_highWaterMark = objectMode ? 16 : 16 * 1024; // default value if (options != nullptr) { int64_t customHightWaterMark = getHighWaterMark(vm, globalObject, isDuplex, options); if (customHightWaterMark >= 0) - highWaterMark = customHightWaterMark; + m_highWaterMark = customHightWaterMark; } - putDirect(vm, JSC::Identifier::fromString(vm, "highWaterMark"_s), JSC::jsNumber(highWaterMark)); putDirect(vm, JSC::Identifier::fromString(vm, "buffer"_s), JSBufferList::create( vm, globalObject, reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferListStructure())); - putDirect(vm, JSC::Identifier::fromString(vm, "length"_s), JSC::jsNumber(0)); putDirect(vm, JSC::Identifier::fromString(vm, "pipes"_s), JSC::constructEmptyArray(globalObject, nullptr, 0)); - putDirect(vm, JSC::Identifier::fromString(vm, "flowing"_s), JSC::jsNull()); - putDirect(vm, JSC::Identifier::fromString(vm, "ended"_s), JSC::jsBoolean(false)); - putDirect(vm, JSC::Identifier::fromString(vm, "endEmitted"_s), JSC::jsBoolean(false)); - // Stream is still being constructed and cannot be - // destroyed until construction finished or failed. - // Async construction is opt in, therefore we start as - // constructed. - putDirect(vm, JSC::Identifier::fromString(vm, "reading"_s), JSC::jsBoolean(false)); - - // A flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - putDirect(vm, JSC::Identifier::fromString(vm, "constructed"_s), JSC::jsBoolean(true)); - - // Whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - putDirect(vm, JSC::Identifier::fromString(vm, "sync"_s), JSC::jsBoolean(true)); - - putDirect(vm, JSC::Identifier::fromString(vm, "needReadable"_s), JSC::jsBoolean(false)); - putDirect(vm, JSC::Identifier::fromString(vm, "emittedReadable"_s), JSC::jsBoolean(false)); - putDirect(vm, JSC::Identifier::fromString(vm, "readableListening"_s), JSC::jsBoolean(false)); - putDirect(vm, JSC::Identifier::fromString(vm, "resumeScheduled"_s), JSC::jsBoolean(false)); - - // Should close be emitted on destroy. Defaults to true. - putDirect(vm, JSC::Identifier::fromString(vm, "errorEmitted"_s), JSC::jsBoolean(false)); if (options == nullptr) { - // Should .destroy() be called after 'end' (and potentially 'finish'). - putDirect(vm, JSC::Identifier::fromString(vm, "emitClose"_s), JSC::jsBoolean(false)); - // Has it been destroyed. - putDirect(vm, JSC::Identifier::fromString(vm, "autoDestroy"_s), JSC::jsBoolean(false)); + m_emitClose = false; + m_autoDestroy = false; } else { - // Should .destroy() be called after 'end' (and potentially 'finish'). - auto emitCloseIdent = JSC::Identifier::fromString(vm, "emitClose"_s); - JSC::JSValue emitCloseVal = options->getDirect(vm, emitCloseIdent); - putDirect(vm, WTFMove(emitCloseIdent), JSC::jsBoolean(!emitCloseVal.isBoolean() || emitCloseVal.toBoolean(globalObject))); + JSC::JSValue emitCloseVal = options->getDirect(vm, JSC::Identifier::fromString(vm, "emitClose"_s)); + m_emitClose = !emitCloseVal.isBoolean() || emitCloseVal.toBoolean(globalObject); // Has it been destroyed. - auto autoDestroyIdent = JSC::Identifier::fromString(vm, "autoDestroy"_s); - JSC::JSValue autoDestroyVal = options->getDirect(vm, autoDestroyIdent); - putDirect(vm, WTFMove(autoDestroyIdent), JSC::jsBoolean(!autoDestroyVal.isBoolean() || autoDestroyVal.toBoolean(globalObject))); + JSC::JSValue autoDestroyVal = options->getDirect(vm, JSC::Identifier::fromString(vm, "autoDestroy"_s)); + m_autoDestroy = !autoDestroyVal.isBoolean() || autoDestroyVal.toBoolean(globalObject); } - // Indicates whether the stream has errored. When true no further - // _read calls, 'data' or 'readable' events should occur. This is needed - // since when autoDestroy is disabled we need a way to tell whether the - // stream has failed. - putDirect(vm, JSC::Identifier::fromString(vm, "destroyed"_s), JSC::jsBoolean(false)); - // Indicates whether the stream has finished destroying. putDirect(vm, JSC::Identifier::fromString(vm, "errored"_s), JSC::jsNull()); - // True if close has been emitted or would have been emitted - // depending on emitClose. - putDirect(vm, JSC::Identifier::fromString(vm, "closed"_s), JSC::jsBoolean(false)); - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - putDirect(vm, JSC::Identifier::fromString(vm, "closeEmitted"_s), JSC::jsBoolean(false)); - // Ref the piped dest which we need a drain event on it // type: null | Writable | Set<Writable>. auto defaultEncodingIdent = JSC::Identifier::fromString(vm, "defaultEncoding"_s); @@ -140,11 +90,6 @@ void JSReadableState::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObj } putDirect(vm, JSC::Identifier::fromString(vm, "awaitDrainWriters"_s), JSC::jsNull()); - // If true, a maybeReadMore has been scheduled. - putDirect(vm, JSC::Identifier::fromString(vm, "multiAwaitDrain"_s), JSC::jsBoolean(false)); - - putDirect(vm, JSC::Identifier::fromString(vm, "readingMore"_s), JSC::jsBoolean(false)); - putDirect(vm, JSC::Identifier::fromString(vm, "dataEmitted"_s), JSC::jsBoolean(false)); auto decoderIdent = JSC::Identifier::fromString(vm, "decoder"_s); auto encodingIdent = JSC::Identifier::fromString(vm, "encoding"_s); @@ -201,38 +146,133 @@ JSC_DEFINE_CUSTOM_GETTER(jsReadableState_pipesCount, (JSGlobalObject * lexicalGl RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(pipes->length()))); } -JSC_DEFINE_CUSTOM_GETTER(jsReadableState_paused, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); - if (!state) { - RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); +#define JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(NAME) \ + static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \ + JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \ + { \ + auto& vm = JSC::getVM(lexicalGlobalObject); \ + auto throwScope = DECLARE_THROW_SCOPE(vm); \ + JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \ + if (!state) { \ + RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \ + } \ + if (state->m_##NAME == 0) \ + RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNull())); \ + RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->m_##NAME > 0))); \ + } \ + static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \ + JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \ + { \ + auto& vm = JSC::getVM(lexicalGlobalObject); \ + auto throwScope = DECLARE_THROW_SCOPE(vm); \ + JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \ + if (!state) { \ + RETURN_IF_EXCEPTION(throwScope, false); \ + } \ + auto value = JSC::JSValue::decode(encodedValue); \ + state->m_##NAME = value.isNull() ? 0 : value.toBoolean(lexicalGlobalObject) ? 1 : -1; \ + RELEASE_AND_RETURN(throwScope, true); \ } - if (state->m_paused == 0) - RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNull())); - RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->m_paused > 0))); -} -JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_paused, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) -{ - auto& vm = JSC::getVM(lexicalGlobalObject); - auto throwScope = DECLARE_THROW_SCOPE(vm); - JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); - if (!state) { - RETURN_IF_EXCEPTION(throwScope, false); +JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(paused) +JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(flowing) + +#undef JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER + +#define JSReadableState_GETTER_SETTER(NAME, TYPE) \ + static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \ + JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \ + { \ + auto& vm = JSC::getVM(lexicalGlobalObject); \ + auto throwScope = DECLARE_THROW_SCOPE(vm); \ + JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \ + if (!state) { \ + RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \ + } \ + RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::js##TYPE(state->m_##NAME))); \ + } \ + \ + static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \ + JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \ + { \ + auto& vm = JSC::getVM(lexicalGlobalObject); \ + auto throwScope = DECLARE_THROW_SCOPE(vm); \ + JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \ + if (!state) { \ + RETURN_IF_EXCEPTION(throwScope, false); \ + } \ + state->m_##NAME = JSC::JSValue::decode(encodedValue).to##TYPE(lexicalGlobalObject); \ + RETURN_IF_EXCEPTION(throwScope, false); \ + RELEASE_AND_RETURN(throwScope, true); \ } - state->m_paused = JSC::JSValue::decode(encodedValue).toBoolean(lexicalGlobalObject) ? 1 : -1; - RELEASE_AND_RETURN(throwScope, true); -} + +#define JSReadableState_BOOLEAN_GETTER_SETTER(NAME) \ + JSReadableState_GETTER_SETTER(NAME, Boolean) + +#define JSReadableState_NUMBER_GETTER_SETTER(NAME) \ + JSReadableState_GETTER_SETTER(NAME, Number) + +JSReadableState_BOOLEAN_GETTER_SETTER(ended) +JSReadableState_BOOLEAN_GETTER_SETTER(endEmitted) +JSReadableState_BOOLEAN_GETTER_SETTER(reading) +JSReadableState_BOOLEAN_GETTER_SETTER(constructed) +JSReadableState_BOOLEAN_GETTER_SETTER(sync) +JSReadableState_BOOLEAN_GETTER_SETTER(needReadable) +JSReadableState_BOOLEAN_GETTER_SETTER(emittedReadable) +JSReadableState_BOOLEAN_GETTER_SETTER(readableListening) +JSReadableState_BOOLEAN_GETTER_SETTER(resumeScheduled) +JSReadableState_BOOLEAN_GETTER_SETTER(errorEmitted) +JSReadableState_BOOLEAN_GETTER_SETTER(emitClose) +JSReadableState_BOOLEAN_GETTER_SETTER(autoDestroy) +JSReadableState_BOOLEAN_GETTER_SETTER(destroyed) +JSReadableState_BOOLEAN_GETTER_SETTER(closed) +JSReadableState_BOOLEAN_GETTER_SETTER(closeEmitted) +JSReadableState_BOOLEAN_GETTER_SETTER(multiAwaitDrain) +JSReadableState_BOOLEAN_GETTER_SETTER(readingMore) +JSReadableState_BOOLEAN_GETTER_SETTER(dataEmitted) + +JSReadableState_NUMBER_GETTER_SETTER(length) +JSReadableState_NUMBER_GETTER_SETTER(highWaterMark) + +#undef JSReadableState_NUMBER_GETTER_SETTER +#undef JSReadableState_BOOLEAN_GETTER_SETTER +#undef JSReadableState_GETTER_SETTER + +#define JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(NAME) \ + { #NAME ""_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_##NAME, setJSReadableState_##NAME } } /* Hash table for prototype */ static const HashTableValue JSReadableStatePrototypeTableValues[] = { { "pipesCount"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_pipesCount, 0 } }, - { "paused"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_paused, setJSReadableState_paused } }, + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(paused), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(flowing), + + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(ended), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(endEmitted), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(reading), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(constructed), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(sync), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(needReadable), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emittedReadable), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readableListening), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(resumeScheduled), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(errorEmitted), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emitClose), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(autoDestroy), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(destroyed), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closed), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closeEmitted), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(multiAwaitDrain), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readingMore), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(dataEmitted), + + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(length), + JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(highWaterMark), }; +#undef JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE + void JSReadableStatePrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis) { Base::finishCreation(vm); |