From a6d68c73b9b9943f2f8ceb5c02a9f2579a3b166a Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 19 Jun 2020 13:12:26 -0700 Subject: [PATCH] squash: group functions by class and fix whitespace --- benchmark/function_args.cc | 86 ++-- benchmark/property_descriptor.cc | 46 +- napi-inl.h | 802 +++++++++++++++---------------- napi.h | 4 +- 4 files changed, 469 insertions(+), 469 deletions(-) diff --git a/benchmark/function_args.cc b/benchmark/function_args.cc index e265bca95..90702872a 100644 --- a/benchmark/function_args.cc +++ b/benchmark/function_args.cc @@ -82,49 +82,49 @@ class FunctionArgs : public Napi::Addon { public: FunctionArgs(Napi::Env env, Napi::Object exports) { // Define the core bindings using plain N-API. - napi_value no_arg_function, one_arg_function, two_arg_function, - three_arg_function, four_arg_function; - napi_status status; - - status = napi_create_function(env, - "noArgFunction", - NAPI_AUTO_LENGTH, - NoArgFunction_Core, - nullptr, - &no_arg_function); - NAPI_THROW_IF_FAILED_VOID(env, status); - - status = napi_create_function(env, - "oneArgFunction", - NAPI_AUTO_LENGTH, - OneArgFunction_Core, - nullptr, - &one_arg_function); - NAPI_THROW_IF_FAILED_VOID(env, status); - - status = napi_create_function(env, - "twoArgFunction", - NAPI_AUTO_LENGTH, - TwoArgFunction_Core, - nullptr, - &two_arg_function); - NAPI_THROW_IF_FAILED_VOID(env, status); - - status = napi_create_function(env, - "threeArgFunction", - NAPI_AUTO_LENGTH, - ThreeArgFunction_Core, - nullptr, - &three_arg_function); - NAPI_THROW_IF_FAILED_VOID(env, status); - - status = napi_create_function(env, - "fourArgFunction", - NAPI_AUTO_LENGTH, - FourArgFunction_Core, - nullptr, - &four_arg_function); - NAPI_THROW_IF_FAILED_VOID(env, status); + napi_value no_arg_function, one_arg_function, two_arg_function, + three_arg_function, four_arg_function; + napi_status status; + + status = napi_create_function(env, + "noArgFunction", + NAPI_AUTO_LENGTH, + NoArgFunction_Core, + nullptr, + &no_arg_function); + NAPI_THROW_IF_FAILED_VOID(env, status); + + status = napi_create_function(env, + "oneArgFunction", + NAPI_AUTO_LENGTH, + OneArgFunction_Core, + nullptr, + &one_arg_function); + NAPI_THROW_IF_FAILED_VOID(env, status); + + status = napi_create_function(env, + "twoArgFunction", + NAPI_AUTO_LENGTH, + TwoArgFunction_Core, + nullptr, + &two_arg_function); + NAPI_THROW_IF_FAILED_VOID(env, status); + + status = napi_create_function(env, + "threeArgFunction", + NAPI_AUTO_LENGTH, + ThreeArgFunction_Core, + nullptr, + &three_arg_function); + NAPI_THROW_IF_FAILED_VOID(env, status); + + status = napi_create_function(env, + "fourArgFunction", + NAPI_AUTO_LENGTH, + FourArgFunction_Core, + nullptr, + &four_arg_function); + NAPI_THROW_IF_FAILED_VOID(env, status); DefineAddon(exports, { InstanceValue("core", DefineProperties(Napi::Object::New(env), { diff --git a/benchmark/property_descriptor.cc b/benchmark/property_descriptor.cc index c1e454bd8..c5e5db648 100644 --- a/benchmark/property_descriptor.cc +++ b/benchmark/property_descriptor.cc @@ -29,32 +29,32 @@ static void Setter(const Napi::CallbackInfo& info) { class PropDescBenchmark : public Napi::Addon { public: PropDescBenchmark(Napi::Env env, Napi::Object exports) { - napi_status status; - napi_property_descriptor core_prop = { - "core", - nullptr, - nullptr, - Getter_Core, - Setter_Core, - nullptr, - napi_enumerable, - nullptr - }; + napi_status status; + napi_property_descriptor core_prop = { + "core", + nullptr, + nullptr, + Getter_Core, + Setter_Core, + nullptr, + napi_enumerable, + nullptr + }; - status = napi_define_properties(env, exports, 1, &core_prop); - NAPI_THROW_IF_FAILED_VOID(env, status); + status = napi_define_properties(env, exports, 1, &core_prop); + NAPI_THROW_IF_FAILED_VOID(env, status); - exports.DefineProperty( - Napi::PropertyDescriptor::Accessor(env, - exports, - "cplusplus", - Getter, - Setter, - napi_enumerable)); + exports.DefineProperty( + Napi::PropertyDescriptor::Accessor(env, + exports, + "cplusplus", + Getter, + Setter, + napi_enumerable)); - exports.DefineProperty( - Napi::PropertyDescriptor::Accessor("templated", - napi_enumerable)); + exports.DefineProperty( + Napi::PropertyDescriptor::Accessor("templated", + napi_enumerable)); DefineAddon(exports, { InstanceAccessor("instance", diff --git a/napi-inl.h b/napi-inl.h index 2ef865f60..fe6cf0f61 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -239,11 +239,11 @@ struct AccessorCallbackData { //////////////////////////////////////////////////////////////////////////////// // Register an add-on based on an initializer function. -#define NODE_API_MODULE(modname, regfunc) \ +#define NODE_API_MODULE(modname, regfunc) \ static napi_value __napi_ ## regfunc(napi_env env, \ - napi_value exports) { \ - return Napi::RegisterModule(env, exports, regfunc); \ - } \ + napi_value exports) { \ + return Napi::RegisterModule(env, exports, regfunc); \ + } \ NAPI_MODULE(modname, __napi_ ## regfunc) // Register an add-on based on a subclass of `Addon` with a custom Node.js @@ -3187,526 +3187,644 @@ inline void InstanceWrap::AttachPropData(napi_env env, } } -//////////////////////////////////////////////////////////////////////////////// -// ObjectWrap class -//////////////////////////////////////////////////////////////////////////////// - -template -inline ObjectWrap::ObjectWrap(const Napi::CallbackInfo& callbackInfo) { - napi_env env = callbackInfo.Env(); - napi_value wrapper = callbackInfo.This(); - napi_status status; - napi_ref ref; - T* instance = static_cast(this); - status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref); - NAPI_THROW_IF_FAILED_VOID(env, status); - - Reference* instanceRef = instance; - *instanceRef = Reference(env, ref); -} - -template -inline ObjectWrap::~ObjectWrap() { - // If the JS object still exists at this point, remove the finalizer added - // through `napi_wrap()`. - if (!IsEmpty()) { - Object object = Value(); - // It is not valid to call `napi_remove_wrap()` with an empty `object`. - // This happens e.g. during garbage collection. - if (!object.IsEmpty() && _construction_failed) { - napi_remove_wrap(Env(), object, nullptr); - } - } -} - -template -inline T* ObjectWrap::Unwrap(Object wrapper) { - T* unwrapped; - napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast(&unwrapped)); - NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr); - return unwrapped; -} - -template -inline Function -ObjectWrap::DefineClass(Napi::Env env, - const char* utf8name, - const size_t props_count, - const napi_property_descriptor* descriptors, - void* data) { - napi_status status; - std::vector props(props_count); - - // We copy the descriptors to a local array because before defining the class - // we must replace static method property descriptors with value property - // descriptors such that the value is a function-valued `napi_value` created - // with `CreateFunction()`. - // - // This replacement could be made for instance methods as well, but V8 aborts - // if we do that, because it expects methods defined on the prototype template - // to have `FunctionTemplate`s. - for (size_t index = 0; index < props_count; index++) { - props[index] = descriptors[index]; - napi_property_descriptor* prop = &props[index]; - if (prop->method == T::StaticMethodCallbackWrapper) { - status = CreateFunction(env, - utf8name, - prop->method, - static_cast(prop->data), - &(prop->value)); - NAPI_THROW_IF_FAILED(env, status, Function()); - prop->method = nullptr; - prop->data = nullptr; - } else if (prop->method == T::StaticVoidMethodCallbackWrapper) { - status = CreateFunction(env, - utf8name, - prop->method, - static_cast(prop->data), - &(prop->value)); - NAPI_THROW_IF_FAILED(env, status, Function()); - prop->method = nullptr; - prop->data = nullptr; - } - } - - napi_value value; - status = napi_define_class(env, - utf8name, - NAPI_AUTO_LENGTH, - T::ConstructorCallbackWrapper, - data, - props_count, - props.data(), - &value); - NAPI_THROW_IF_FAILED(env, status, Function()); - - // After defining the class we iterate once more over the property descriptors - // and attach the data associated with accessors and instance methods to the - // newly created JavaScript class. - for (size_t idx = 0; idx < props_count; idx++) { - const napi_property_descriptor* prop = &props[idx]; - - if (prop->getter == T::StaticGetterCallbackWrapper || - prop->setter == T::StaticSetterCallbackWrapper) { - status = Napi::details::AttachData(env, - value, - static_cast(prop->data)); - NAPI_THROW_IF_FAILED(env, status, Function()); - } else { - // InstanceWrap::AttachPropData is responsible for attaching the data - // of instance methods and accessors. - T::AttachPropData(env, value, prop); - } - } - - return Function(env, value); -} - -template -inline Function ObjectWrap::DefineClass( - Napi::Env env, - const char* utf8name, - const std::initializer_list>& properties, - void* data) { - return DefineClass(env, - utf8name, - properties.size(), - reinterpret_cast(properties.begin()), - data); -} - -template -inline Function ObjectWrap::DefineClass( - Napi::Env env, - const char* utf8name, - const std::vector>& properties, - void* data) { - return DefineClass(env, - utf8name, - properties.size(), - reinterpret_cast(properties.data()), - data); -} - template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, - StaticVoidMethodCallback method, + InstanceVoidMethodCallback method, napi_property_attributes attributes, void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); + InstanceVoidMethodCallbackData* callbackData = + new InstanceVoidMethodCallbackData({ method, data}); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = T::StaticVoidMethodCallbackWrapper; + desc.method = T::InstanceVoidMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, - StaticMethodCallback method, + InstanceMethodCallback method, napi_property_attributes attributes, void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); + InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = T::StaticMethodCallbackWrapper; + desc.method = T::InstanceMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, - StaticVoidMethodCallback method, + InstanceVoidMethodCallback method, napi_property_attributes attributes, void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); + InstanceVoidMethodCallbackData* callbackData = + new InstanceVoidMethodCallbackData({ method, data}); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = T::StaticVoidMethodCallbackWrapper; + desc.method = T::InstanceVoidMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, - StaticMethodCallback method, + InstanceMethodCallback method, napi_property_attributes attributes, void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); + InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = T::StaticMethodCallbackWrapper; + desc.method = T::InstanceMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +template ::InstanceVoidMethodCallback method> +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; + desc.method = &InstanceWrap::WrappedMethod; desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, +template ::InstanceMethodCallback method> +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( + const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; + desc.utf8name = utf8name; + desc.method = &InstanceWrap::WrappedMethod; desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, +template ::InstanceVoidMethodCallback method> +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( + Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; + desc.name = name; + desc.method = &InstanceWrap::WrappedMethod; desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( +template ::InstanceMethodCallback method> +inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; + desc.method = &InstanceWrap::WrappedMethod; desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( +inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( const char* utf8name, - StaticGetterCallback getter, - StaticSetterCallback setter, + InstanceGetterCallback getter, + InstanceSetterCallback setter, napi_property_attributes attributes, void* data) { - StaticAccessorCallbackData* callbackData = - new StaticAccessorCallbackData({ getter, setter, data }); + InstanceAccessorCallbackData* callbackData = + new InstanceAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; + desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; + desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( +inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( Symbol name, - StaticGetterCallback getter, - StaticSetterCallback setter, + InstanceGetterCallback getter, + InstanceSetterCallback setter, napi_property_attributes attributes, void* data) { - StaticAccessorCallbackData* callbackData = - new StaticAccessorCallbackData({ getter, setter, data }); + InstanceAccessorCallbackData* callbackData = + new InstanceAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; + desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; + desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticGetterCallback getter, - typename ObjectWrap::StaticSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( +template ::InstanceGetterCallback getter, + typename InstanceWrap::InstanceSetterCallback setter> +inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); - desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); + desc.getter = This::WrapGetter(This::GetterTag()); + desc.setter = This::WrapSetter(This::SetterTag()); desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; return desc; } template -template ::StaticGetterCallback getter, - typename ObjectWrap::StaticSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( +template ::InstanceGetterCallback getter, + typename InstanceWrap::InstanceSetterCallback setter> +inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); - desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); + desc.getter = This::WrapGetter(This::GetterTag()); + desc.setter = This::WrapSetter(This::SetterTag()); desc.data = data; - desc.attributes = static_cast(attributes | napi_static); + desc.attributes = attributes; + return desc; +} + +template +inline ClassPropertyDescriptor InstanceWrap::InstanceValue( + const char* utf8name, + Napi::Value value, + napi_property_attributes attributes) { + napi_property_descriptor desc = napi_property_descriptor(); + desc.utf8name = utf8name; + desc.value = value; + desc.attributes = attributes; + return desc; +} + +template +inline ClassPropertyDescriptor InstanceWrap::InstanceValue( + Symbol name, + Napi::Value value, + napi_property_attributes attributes) { + napi_property_descriptor desc = napi_property_descriptor(); + desc.name = name; + desc.value = value; + desc.attributes = attributes; return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +inline napi_value InstanceWrap::InstanceVoidMethodCallbackWrapper( + napi_env env, + napi_callback_info info) { + return details::WrapCallback([&] { + CallbackInfo callbackInfo(env, info); + InstanceVoidMethodCallbackData* callbackData = + reinterpret_cast(callbackInfo.Data()); + callbackInfo.SetData(callbackData->data); + T* instance = T::Unwrap(callbackInfo.This().As()); + auto cb = callbackData->callback; + (instance->*cb)(callbackInfo); + return nullptr; + }); +} + +template +inline napi_value InstanceWrap::InstanceMethodCallbackWrapper( + napi_env env, + napi_callback_info info) { + return details::WrapCallback([&] { + CallbackInfo callbackInfo(env, info); + InstanceMethodCallbackData* callbackData = + reinterpret_cast(callbackInfo.Data()); + callbackInfo.SetData(callbackData->data); + T* instance = T::Unwrap(callbackInfo.This().As()); + auto cb = callbackData->callback; + return (instance->*cb)(callbackInfo); + }); +} + +template +inline napi_value InstanceWrap::InstanceGetterCallbackWrapper( + napi_env env, + napi_callback_info info) { + return details::WrapCallback([&] { + CallbackInfo callbackInfo(env, info); + InstanceAccessorCallbackData* callbackData = + reinterpret_cast(callbackInfo.Data()); + callbackInfo.SetData(callbackData->data); + T* instance = T::Unwrap(callbackInfo.This().As()); + auto cb = callbackData->getterCallback; + return (instance->*cb)(callbackInfo); + }); +} + +template +inline napi_value InstanceWrap::InstanceSetterCallbackWrapper( + napi_env env, + napi_callback_info info) { + return details::WrapCallback([&] { + CallbackInfo callbackInfo(env, info); + InstanceAccessorCallbackData* callbackData = + reinterpret_cast(callbackInfo.Data()); + callbackInfo.SetData(callbackData->data); + T* instance = T::Unwrap(callbackInfo.This().As()); + auto cb = callbackData->setterCallback; + (instance->*cb)(callbackInfo, callbackInfo[0]); + return nullptr; + }); +} + +template +template ::InstanceVoidMethodCallback method> +inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { + return details::WrapCallback([&] { + const CallbackInfo cbInfo(env, info); + T* instance = T::Unwrap(cbInfo.This().As()); + (instance->*method)(cbInfo); + return nullptr; + }); +} + +template +template ::InstanceMethodCallback method> +inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { + return details::WrapCallback([&] { + const CallbackInfo cbInfo(env, info); + T* instance = T::Unwrap(cbInfo.This().As()); + return (instance->*method)(cbInfo); + }); +} + +template +template ::InstanceSetterCallback method> +inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { + return details::WrapCallback([&] { + const CallbackInfo cbInfo(env, info); + T* instance = T::Unwrap(cbInfo.This().As()); + (instance->*method)(cbInfo, cbInfo[0]); + return nullptr; + }); +} + +//////////////////////////////////////////////////////////////////////////////// +// ObjectWrap class +//////////////////////////////////////////////////////////////////////////////// + +template +inline ObjectWrap::ObjectWrap(const Napi::CallbackInfo& callbackInfo) { + napi_env env = callbackInfo.Env(); + napi_value wrapper = callbackInfo.This(); + napi_status status; + napi_ref ref; + T* instance = static_cast(this); + status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref); + NAPI_THROW_IF_FAILED_VOID(env, status); + + Reference* instanceRef = instance; + *instanceRef = Reference(env, ref); +} + +template +inline ObjectWrap::~ObjectWrap() { + // If the JS object still exists at this point, remove the finalizer added + // through `napi_wrap()`. + if (!IsEmpty()) { + Object object = Value(); + // It is not valid to call `napi_remove_wrap()` with an empty `object`. + // This happens e.g. during garbage collection. + if (!object.IsEmpty() && _construction_failed) { + napi_remove_wrap(Env(), object, nullptr); + } + } +} + +template +inline T* ObjectWrap::Unwrap(Object wrapper) { + T* unwrapped; + napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast(&unwrapped)); + NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr); + return unwrapped; +} + +template +inline Function +ObjectWrap::DefineClass(Napi::Env env, + const char* utf8name, + const size_t props_count, + const napi_property_descriptor* descriptors, + void* data) { + napi_status status; + std::vector props(props_count); + + // We copy the descriptors to a local array because before defining the class + // we must replace static method property descriptors with value property + // descriptors such that the value is a function-valued `napi_value` created + // with `CreateFunction()`. + // + // This replacement could be made for instance methods as well, but V8 aborts + // if we do that, because it expects methods defined on the prototype template + // to have `FunctionTemplate`s. + for (size_t index = 0; index < props_count; index++) { + props[index] = descriptors[index]; + napi_property_descriptor* prop = &props[index]; + if (prop->method == T::StaticMethodCallbackWrapper) { + status = CreateFunction(env, + utf8name, + prop->method, + static_cast(prop->data), + &(prop->value)); + NAPI_THROW_IF_FAILED(env, status, Function()); + prop->method = nullptr; + prop->data = nullptr; + } else if (prop->method == T::StaticVoidMethodCallbackWrapper) { + status = CreateFunction(env, + utf8name, + prop->method, + static_cast(prop->data), + &(prop->value)); + NAPI_THROW_IF_FAILED(env, status, Function()); + prop->method = nullptr; + prop->data = nullptr; + } + } + + napi_value value; + status = napi_define_class(env, + utf8name, + NAPI_AUTO_LENGTH, + T::ConstructorCallbackWrapper, + data, + props_count, + props.data(), + &value); + NAPI_THROW_IF_FAILED(env, status, Function()); + + // After defining the class we iterate once more over the property descriptors + // and attach the data associated with accessors and instance methods to the + // newly created JavaScript class. + for (size_t idx = 0; idx < props_count; idx++) { + const napi_property_descriptor* prop = &props[idx]; + + if (prop->getter == T::StaticGetterCallbackWrapper || + prop->setter == T::StaticSetterCallbackWrapper) { + status = Napi::details::AttachData(env, + value, + static_cast(prop->data)); + NAPI_THROW_IF_FAILED(env, status, Function()); + } else { + // InstanceWrap::AttachPropData is responsible for attaching the data + // of instance methods and accessors. + T::AttachPropData(env, value, prop); + } + } + + return Function(env, value); +} + +template +inline Function ObjectWrap::DefineClass( + Napi::Env env, + const char* utf8name, + const std::initializer_list>& properties, + void* data) { + return DefineClass(env, + utf8name, + properties.size(), + reinterpret_cast(properties.begin()), + data); +} + +template +inline Function ObjectWrap::DefineClass( + Napi::Env env, + const char* utf8name, + const std::vector>& properties, + void* data) { + return DefineClass(env, + utf8name, + properties.size(), + reinterpret_cast(properties.data()), + data); +} + +template +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, - InstanceVoidMethodCallback method, + StaticVoidMethodCallback method, napi_property_attributes attributes, void* data) { - InstanceVoidMethodCallbackData* callbackData = - new InstanceVoidMethodCallbackData({ method, data}); + StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = T::InstanceVoidMethodCallbackWrapper; + desc.method = T::StaticVoidMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, - InstanceMethodCallback method, + StaticMethodCallback method, napi_property_attributes attributes, void* data) { - InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); + StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = T::InstanceMethodCallbackWrapper; + desc.method = T::StaticMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, - InstanceVoidMethodCallback method, + StaticVoidMethodCallback method, napi_property_attributes attributes, void* data) { - InstanceVoidMethodCallbackData* callbackData = - new InstanceVoidMethodCallbackData({ method, data}); + StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = T::InstanceVoidMethodCallbackWrapper; + desc.method = T::StaticVoidMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, - InstanceMethodCallback method, + StaticMethodCallback method, napi_property_attributes attributes, void* data) { - InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); + StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = T::InstanceMethodCallbackWrapper; + desc.method = T::StaticMethodCallbackWrapper; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceVoidMethodCallback method> -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +template ::StaticVoidMethodCallback method> +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.method = &InstanceWrap::WrappedMethod; + desc.method = &ObjectWrap::WrappedMethod; desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceMethodCallback method> -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( - const char* utf8name, +template ::StaticVoidMethodCallback method> +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( + Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &InstanceWrap::WrappedMethod; + desc.name = name; + desc.method = &ObjectWrap::WrappedMethod; desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceVoidMethodCallback method> -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( - Symbol name, +template ::StaticMethodCallback method> +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( + const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &InstanceWrap::WrappedMethod; + desc.utf8name = utf8name; + desc.method = &ObjectWrap::WrappedMethod; desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceMethodCallback method> -inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( +template ::StaticMethodCallback method> +inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.method = &InstanceWrap::WrappedMethod; + desc.method = &ObjectWrap::WrappedMethod; desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( +inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( const char* utf8name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, + StaticGetterCallback getter, + StaticSetterCallback setter, napi_property_attributes attributes, void* data) { - InstanceAccessorCallbackData* callbackData = - new InstanceAccessorCallbackData({ getter, setter, data }); + StaticAccessorCallbackData* callbackData = + new StaticAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; + desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; + desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( +inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( Symbol name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, + StaticGetterCallback getter, + StaticSetterCallback setter, napi_property_attributes attributes, void* data) { - InstanceAccessorCallbackData* callbackData = - new InstanceAccessorCallbackData({ getter, setter, data }); + StaticAccessorCallbackData* callbackData = + new StaticAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; + desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; + desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; desc.data = callbackData; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceGetterCallback getter, - typename InstanceWrap::InstanceSetterCallback setter> -inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( +template ::StaticGetterCallback getter, + typename ObjectWrap::StaticSetterCallback setter> +inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; - desc.getter = This::WrapGetter(This::GetterTag()); - desc.setter = This::WrapSetter(This::SetterTag()); + desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); + desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } template -template ::InstanceGetterCallback getter, - typename InstanceWrap::InstanceSetterCallback setter> -inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( +template ::StaticGetterCallback getter, + typename ObjectWrap::StaticSetterCallback setter> +inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; - desc.getter = This::WrapGetter(This::GetterTag()); - desc.setter = This::WrapSetter(This::SetterTag()); + desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); + desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); desc.data = data; - desc.attributes = attributes; + desc.attributes = static_cast(attributes | napi_static); return desc; } @@ -3730,30 +3848,6 @@ inline ClassPropertyDescriptor ObjectWrap::StaticValue(Symbol name, return desc; } -template -inline ClassPropertyDescriptor InstanceWrap::InstanceValue( - const char* utf8name, - Napi::Value value, - napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor InstanceWrap::InstanceValue( - Symbol name, - Napi::Value value, - napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - template inline void ObjectWrap::Finalize(Napi::Env /*env*/) {} @@ -3846,68 +3940,6 @@ inline napi_value ObjectWrap::StaticSetterCallbackWrapper( }); } -template -inline napi_value InstanceWrap::InstanceVoidMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceVoidMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = T::Unwrap(callbackInfo.This().As()); - auto cb = callbackData->callback; - (instance->*cb)(callbackInfo); - return nullptr; - }); -} - -template -inline napi_value InstanceWrap::InstanceMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = T::Unwrap(callbackInfo.This().As()); - auto cb = callbackData->callback; - return (instance->*cb)(callbackInfo); - }); -} - -template -inline napi_value InstanceWrap::InstanceGetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = T::Unwrap(callbackInfo.This().As()); - auto cb = callbackData->getterCallback; - return (instance->*cb)(callbackInfo); - }); -} - -template -inline napi_value InstanceWrap::InstanceSetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = T::Unwrap(callbackInfo.This().As()); - auto cb = callbackData->setterCallback; - (instance->*cb)(callbackInfo, callbackInfo[0]); - return nullptr; - }); -} - template inline void ObjectWrap::FinalizeCallback(napi_env env, void* data, void* /*hint*/) { T* instance = static_cast(data); @@ -3932,27 +3964,6 @@ inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info }); } -template -template ::InstanceVoidMethodCallback method> -inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = T::Unwrap(cbInfo.This().As()); - (instance->*method)(cbInfo); - return nullptr; - }); -} - -template -template ::InstanceMethodCallback method> -inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = T::Unwrap(cbInfo.This().As()); - return (instance->*method)(cbInfo); - }); -} - template template ::StaticSetterCallback method> inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { @@ -3963,17 +3974,6 @@ inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info }); } -template -template ::InstanceSetterCallback method> -inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = T::Unwrap(cbInfo.This().As()); - (instance->*method)(cbInfo, cbInfo[0]); - return nullptr; - }); -} - //////////////////////////////////////////////////////////////////////////////// // HandleScope class //////////////////////////////////////////////////////////////////////////////// diff --git a/napi.h b/napi.h index 7c0ec5c46..b4b7c8eff 100644 --- a/napi.h +++ b/napi.h @@ -1910,8 +1910,8 @@ namespace Napi { template static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - template struct StaticGetterTag {}; - template struct StaticSetterTag {}; + template struct StaticGetterTag {}; + template struct StaticSetterTag {}; template static napi_callback WrapStaticGetter(StaticGetterTag) noexcept { return &This::WrappedMethod; }