Skip to content

Commit

Permalink
object: add templated property descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabriel Schulhof committed Nov 27, 2019
1 parent f677794 commit 8ec7f34
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 0 deletions.
107 changes: 107 additions & 0 deletions napi-inl.h
Expand Up @@ -2732,6 +2732,113 @@ inline void CallbackInfo::SetData(void* data) {
// PropertyDescriptor class
////////////////////////////////////////////////////////////////////////////////

template <PropertyDescriptor::GetterCallback Getter>
PropertyDescriptor
PropertyDescriptor::Accessor(const char* utf8name,
napi_property_attributes attributes,
void* data) {
return PropertyDescriptor({
utf8name,
nullptr,
nullptr,
GetterCallbackWrapper<Getter>,
nullptr,
nullptr,
attributes,
data
});
}

template <PropertyDescriptor::GetterCallback Getter>
PropertyDescriptor
PropertyDescriptor::Accessor(const std::string& utf8name,
napi_property_attributes attributes,
void* data) {
return Accessor<Getter>(utf8name.c_str(), attributes, data);
}

template <PropertyDescriptor::GetterCallback Getter>
PropertyDescriptor
PropertyDescriptor::Accessor(Name name,
napi_property_attributes attributes,
void* data) {
return PropertyDescriptor({
nullptr,
name,
nullptr,
GetterCallbackWrapper<Getter>,
nullptr,
nullptr,
attributes,
data
});
}

template <
PropertyDescriptor::GetterCallback Getter,
PropertyDescriptor::SetterCallback Setter>
PropertyDescriptor
PropertyDescriptor::Accessor(const char* utf8name,
napi_property_attributes attributes,
void* data) {
return PropertyDescriptor({
utf8name,
nullptr,
nullptr,
GetterCallbackWrapper<Getter>,
SetterCallbackWrapper<Setter>,
nullptr,
attributes,
data
});
}

template <
PropertyDescriptor::GetterCallback Getter,
PropertyDescriptor::SetterCallback Setter>
PropertyDescriptor
PropertyDescriptor::Accessor(const std::string& utf8name,
napi_property_attributes attributes,
void* data) {
return Accessor<Getter, Setter>(utf8name.c_str(), attributes, data);
}

template <
PropertyDescriptor::GetterCallback Getter,
PropertyDescriptor::SetterCallback Setter>
PropertyDescriptor
PropertyDescriptor::Accessor(Name name,
napi_property_attributes attributes,
void* data) {
return PropertyDescriptor({
nullptr,
name,
nullptr,
GetterCallbackWrapper<Getter>,
SetterCallbackWrapper<Setter>,
nullptr,
attributes,
data
});
}

template <PropertyDescriptor::GetterCallback Getter>
napi_value
PropertyDescriptor::GetterCallbackWrapper(napi_env env,
napi_callback_info info) {
CallbackInfo cbInfo(env, info);
return Getter(cbInfo);
}

template <PropertyDescriptor::SetterCallback Setter>
napi_value
PropertyDescriptor::SetterCallbackWrapper(napi_env env,
napi_callback_info info) {
CallbackInfo cbInfo(env, info);
Setter(cbInfo, cbInfo[0]);
return nullptr;
}

template <typename Getter>
inline PropertyDescriptor
PropertyDescriptor::Accessor(Napi::Env env,
Expand Down
37 changes: 37 additions & 0 deletions napi.h
Expand Up @@ -1407,6 +1407,9 @@ namespace Napi {

class PropertyDescriptor {
public:
typedef Napi::Value (*GetterCallback)(const CallbackInfo& info);
typedef void (*SetterCallback)(const CallbackInfo& info, const Napi::Value& value);

#ifndef NODE_ADDON_API_DISABLE_DEPRECATED
template <typename Getter>
static PropertyDescriptor Accessor(const char* utf8name,
Expand Down Expand Up @@ -1474,6 +1477,36 @@ namespace Napi {
void* data = nullptr);
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED

template <GetterCallback Getter>
static PropertyDescriptor Accessor(const char* utf8name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <GetterCallback Getter>
static PropertyDescriptor Accessor(const std::string& utf8name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <GetterCallback Getter>
static PropertyDescriptor Accessor(Name name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <GetterCallback Getter, SetterCallback Setter>
static PropertyDescriptor Accessor(const char* utf8name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <GetterCallback Getter, SetterCallback Setter>
static PropertyDescriptor Accessor(const std::string& utf8name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <GetterCallback Getter, SetterCallback Setter>
static PropertyDescriptor Accessor(Name name,
napi_property_attributes attributes = napi_default,
void* data = nullptr);

template <typename Getter>
static PropertyDescriptor Accessor(Napi::Env env,
Napi::Object object,
Expand Down Expand Up @@ -1559,6 +1592,10 @@ namespace Napi {
operator const napi_property_descriptor&() const;

private:
template <GetterCallback Getter>
static napi_value GetterCallbackWrapper(napi_env env, napi_callback_info info);
template <SetterCallback Setter>
static napi_value SetterCallbackWrapper(napi_env env, napi_callback_info info);
napi_property_descriptor _desc;
};

Expand Down
47 changes: 47 additions & 0 deletions test/object/object.cc
Expand Up @@ -85,6 +85,20 @@ void DefineProperties(const CallbackInfo& info) {
PropertyDescriptor::Accessor(env, obj, "readwriteAccessor", TestGetter, TestSetter),
PropertyDescriptor::Accessor(env, obj, "readonlyAccessorWithUserData", TestGetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor(env, obj, "readwriteAccessorWithUserData", TestGetterWithUserData, TestSetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),

PropertyDescriptor::Accessor<TestGetter>("readonlyAccessorT"),
PropertyDescriptor::Accessor<TestGetter, TestSetter>(
"readwriteAccessorT"),
PropertyDescriptor::Accessor<TestGetterWithUserData>(
"readonlyAccessorWithUserDataT",
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor<
TestGetterWithUserData,
TestSetterWithUserData>("readwriteAccessorWithUserDataT",
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),

PropertyDescriptor::Value("readonlyValue", trueValue),
PropertyDescriptor::Value("readwriteValue", trueValue, napi_writable),
PropertyDescriptor::Value("enumerableValue", trueValue, napi_enumerable),
Expand All @@ -100,6 +114,12 @@ void DefineProperties(const CallbackInfo& info) {
std::string str2("readwriteAccessor");
std::string str1a("readonlyAccessorWithUserData");
std::string str2a("readwriteAccessorWithUserData");

std::string str1t("readonlyAccessorT");
std::string str2t("readwriteAccessorT");
std::string str1at("readonlyAccessorWithUserDataT");
std::string str2at("readwriteAccessorWithUserDataT");

std::string str3("readonlyValue");
std::string str4("readwriteValue");
std::string str5("enumerableValue");
Expand All @@ -111,6 +131,18 @@ void DefineProperties(const CallbackInfo& info) {
PropertyDescriptor::Accessor(env, obj, str2, TestGetter, TestSetter),
PropertyDescriptor::Accessor(env, obj, str1a, TestGetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor(env, obj, str2a, TestGetterWithUserData, TestSetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),

PropertyDescriptor::Accessor<TestGetter>(str1t),
PropertyDescriptor::Accessor<TestGetter, TestSetter>(str2t),
PropertyDescriptor::Accessor<TestGetterWithUserData>(str1at,
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor<
TestGetterWithUserData,
TestSetterWithUserData>(str2at,
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),

PropertyDescriptor::Value(str3, trueValue),
PropertyDescriptor::Value(str4, trueValue, napi_writable),
PropertyDescriptor::Value(str5, trueValue, napi_enumerable),
Expand All @@ -127,6 +159,21 @@ void DefineProperties(const CallbackInfo& info) {
Napi::String::New(env, "readonlyAccessorWithUserData"), TestGetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor(env, obj,
Napi::String::New(env, "readwriteAccessorWithUserData"), TestGetterWithUserData, TestSetterWithUserData, napi_property_attributes::napi_default, reinterpret_cast<void*>(holder)),

PropertyDescriptor::Accessor<TestGetter>(
Napi::String::New(env, "readonlyAccessorT")),
PropertyDescriptor::Accessor<TestGetter, TestSetter>(
Napi::String::New(env, "readwriteAccessorT")),
PropertyDescriptor::Accessor<TestGetterWithUserData>(
Napi::String::New(env, "readonlyAccessorWithUserDataT"),
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),
PropertyDescriptor::Accessor<
TestGetterWithUserData, TestSetterWithUserData>(
Napi::String::New(env, "readwriteAccessorWithUserDataT"),
napi_property_attributes::napi_default,
reinterpret_cast<void*>(holder)),

PropertyDescriptor::Value(
Napi::String::New(env, "readonlyValue"), trueValue),
PropertyDescriptor::Value(
Expand Down
26 changes: 26 additions & 0 deletions test/object/object.js
Expand Up @@ -22,6 +22,7 @@ function test(binding) {
const obj = {};
binding.object.defineProperties(obj, nameType);

// accessors
assertPropertyIsNot(obj, 'readonlyAccessor', 'enumerable');
assertPropertyIsNot(obj, 'readonlyAccessor', 'configurable');
assert.strictEqual(obj.readonlyAccessor, true);
Expand All @@ -44,6 +45,30 @@ function test(binding) {
obj.readwriteAccessorWithUserData = -14;
assert.strictEqual(obj.readwriteAccessorWithUserData, -14);

// templated accessors
assertPropertyIsNot(obj, 'readonlyAccessorT', 'enumerable');
assertPropertyIsNot(obj, 'readonlyAccessorT', 'configurable');
assert.strictEqual(obj.readonlyAccessor, true);

assertPropertyIsNot(obj, 'readonlyAccessorWithUserDataT', 'enumerable');
assertPropertyIsNot(obj, 'readonlyAccessorWithUserDataT', 'configurable');
assert.strictEqual(obj.readonlyAccessorWithUserData, 1234, nameType);

assertPropertyIsNot(obj, 'readwriteAccessorT', 'enumerable');
assertPropertyIsNot(obj, 'readwriteAccessorT', 'configurable');
obj.readwriteAccessor = false;
assert.strictEqual(obj.readwriteAccessor, false);
obj.readwriteAccessor = true;
assert.strictEqual(obj.readwriteAccessor, true);

assertPropertyIsNot(obj, 'readwriteAccessorWithUserDataT', 'enumerable');
assertPropertyIsNot(obj, 'readwriteAccessorWithUserDataT', 'configurable');
obj.readwriteAccessorWithUserData = 2;
assert.strictEqual(obj.readwriteAccessorWithUserData, 2);
obj.readwriteAccessorWithUserData = -14;
assert.strictEqual(obj.readwriteAccessorWithUserData, -14);

// values
assertPropertyIsNot(obj, 'readonlyValue', 'writable');
assertPropertyIsNot(obj, 'readonlyValue', 'enumerable');
assertPropertyIsNot(obj, 'readonlyValue', 'configurable');
Expand All @@ -65,6 +90,7 @@ function test(binding) {
assertPropertyIsNot(obj, 'configurableValue', 'enumerable');
assertPropertyIs(obj, 'configurableValue', 'configurable');

// functions
assertPropertyIsNot(obj, 'function', 'writable');
assertPropertyIsNot(obj, 'function', 'enumerable');
assertPropertyIsNot(obj, 'function', 'configurable');
Expand Down

0 comments on commit 8ec7f34

Please sign in to comment.