Skip to content

Commit

Permalink
objectwrap: implement missing descriptor definitions for symbols
Browse files Browse the repository at this point in the history
Implements descriptor definitions with symbols for `StaticMethod`,
`StaticAccessor`, `InstanceAccessor`, `StaticValue`, `InstanceValue`.

Ref: nodejs#279
  • Loading branch information
Philipp Renoth committed Jun 11, 2018
1 parent 43ff9fa commit 2bd929a
Show file tree
Hide file tree
Showing 4 changed files with 397 additions and 77 deletions.
96 changes: 96 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2739,6 +2739,40 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
Symbol name,
StaticVoidMethodCallback method,
napi_property_attributes attributes,
void* data) {
// TODO: Delete when the class is destroyed
StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data });

napi_property_descriptor desc = napi_property_descriptor();
desc.name = name;
desc.method = T::StaticVoidMethodCallbackWrapper;
desc.data = callbackData;
desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
Symbol name,
StaticMethodCallback method,
napi_property_attributes attributes,
void* data) {
// TODO: Delete when the class is destroyed
StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data });

napi_property_descriptor desc = napi_property_descriptor();
desc.name = name;
desc.method = T::StaticMethodCallbackWrapper;
desc.data = callbackData;
desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
const char* utf8name,
Expand All @@ -2759,6 +2793,26 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
Symbol name,
StaticGetterCallback getter,
StaticSetterCallback setter,
napi_property_attributes attributes,
void* data) {
// TODO: Delete when the class is destroyed
StaticAccessorCallbackData* callbackData =
new StaticAccessorCallbackData({ 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.data = callbackData;
desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
const char* utf8name,
Expand Down Expand Up @@ -2849,6 +2903,26 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
Symbol name,
InstanceGetterCallback getter,
InstanceSetterCallback setter,
napi_property_attributes attributes,
void* data) {
// TODO: Delete when the class is destroyed
InstanceAccessorCallbackData* callbackData =
new InstanceAccessorCallbackData({ 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.data = callbackData;
desc.attributes = attributes;
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
Napi::Value value, napi_property_attributes attributes) {
Expand All @@ -2859,6 +2933,16 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8nam
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
Napi::Value value, napi_property_attributes attributes) {
napi_property_descriptor desc = napi_property_descriptor();
desc.name = name;
desc.value = value;
desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
const char* utf8name,
Expand All @@ -2871,6 +2955,18 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
return desc;
}

template <typename T>
inline ClassPropertyDescriptor<T> ObjectWrap<T>::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 <typename T>
inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
napi_env env,
Expand Down
24 changes: 24 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1395,11 +1395,24 @@ namespace Napi {
StaticMethodCallback method,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor StaticMethod(Symbol name,
StaticVoidMethodCallback method,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor StaticMethod(Symbol name,
StaticMethodCallback method,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor StaticAccessor(const char* utf8name,
StaticGetterCallback getter,
StaticSetterCallback setter,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor StaticAccessor(Symbol name,
StaticGetterCallback getter,
StaticSetterCallback setter,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor InstanceMethod(const char* utf8name,
InstanceVoidMethodCallback method,
napi_property_attributes attributes = napi_default,
Expand All @@ -1421,12 +1434,23 @@ namespace Napi {
InstanceSetterCallback setter,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor InstanceAccessor(Symbol name,
InstanceGetterCallback getter,
InstanceSetterCallback setter,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
static PropertyDescriptor StaticValue(const char* utf8name,
Napi::Value value,
napi_property_attributes attributes = napi_default);
static PropertyDescriptor StaticValue(Symbol name,
Napi::Value value,
napi_property_attributes attributes = napi_default);
static PropertyDescriptor InstanceValue(const char* utf8name,
Napi::Value value,
napi_property_attributes attributes = napi_default);
static PropertyDescriptor InstanceValue(Symbol name,
Napi::Value value,
napi_property_attributes attributes = napi_default);

private:
static napi_value ConstructorCallbackWrapper(napi_env env, napi_callback_info info);
Expand Down
120 changes: 86 additions & 34 deletions test/objectwrap.cc
Original file line number Diff line number Diff line change
@@ -1,66 +1,118 @@
#include <napi.h>

class TestIter : public Napi::ObjectWrap<TestIter> {
public:
TestIter(const Napi::CallbackInfo& info) : Napi::ObjectWrap<TestIter>(info) {}
Napi::ObjectReference testStaticContextRef;

Napi::Value Next(const Napi::CallbackInfo& info) {
auto object = Napi::Object::New(info.Env());
object.Set("done", Napi::Boolean::New(info.Env(), true));
return object;
}
Napi::Value StaticGetter(const Napi::CallbackInfo& info) {
return testStaticContextRef.Value().Get("value");
}

static Napi::FunctionReference Initialize(Napi::Env env) {
return Napi::Persistent(DefineClass(env, "TestIter", {
InstanceMethod("next", &TestIter::Next),
}));
}
};
void StaticSetter(const Napi::CallbackInfo& info, const Napi::Value& value) {
testStaticContextRef.Value().Set("value", value);
}

Napi::Value TestStaticMethod(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString();
return Napi::String::New(info.Env(), str + " static");
}

Napi::Value TestStaticMethodInternal(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString();
return Napi::String::New(info.Env(), str + " static internal");
}

class Test : public Napi::ObjectWrap<Test> {
public:
Test(const Napi::CallbackInfo& info) :
Napi::ObjectWrap<Test>(info),
Constructor(TestIter::Initialize(info.Env())) {
Napi::ObjectWrap<Test>(info) {
}

void SetMethod(const Napi::CallbackInfo& info) {
value = info[0].As<Napi::Number>();
void Setter(const Napi::CallbackInfo& info, const Napi::Value& value) {
value_ = value.ToString();
}

Napi::Value GetMethod(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), value);
Napi::Value Getter(const Napi::CallbackInfo& info) {
return Napi::String::New(info.Env(), value_);
}

Napi::Value Iter(const Napi::CallbackInfo& info) {
return Constructor.New({});
Napi::Value TestMethod(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString();
return Napi::String::New(info.Env(), str + " instance");
}

void Setter(const Napi::CallbackInfo& info, const Napi::Value& new_value) {
value = new_value.As<Napi::Number>();
Napi::Value TestMethodInternal(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString();
return Napi::String::New(info.Env(), str + " instance internal");
}

Napi::Value Getter(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), value);
Napi::Value ToStringTag(const Napi::CallbackInfo& info) {
return Napi::String::From(info.Env(), "TestTag");
}

// creates dummy array, returns `([value])[Symbol.iterator]()`
Napi::Value Iterator(const Napi::CallbackInfo& info) {
Napi::Array array = Napi::Array::New(info.Env());
array.Set(array.Length(), Napi::String::From(info.Env(), value_));
return array.Get(Napi::Symbol::WellKnown(info.Env(), "iterator")).As<Napi::Function>().Call(array, {});
}

static void Initialize(Napi::Env env, Napi::Object exports) {

Napi::Symbol kTestStaticValueInternal = Napi::Symbol::New(env, "kTestStaticValueInternal");
Napi::Symbol kTestStaticAccessorInternal = Napi::Symbol::New(env, "kTestStaticAccessorInternal");
Napi::Symbol kTestStaticMethodInternal = Napi::Symbol::New(env, "kTestStaticMethodInternal");

Napi::Symbol kTestValueInternal = Napi::Symbol::New(env, "kTestValueInternal");
Napi::Symbol kTestAccessorInternal = Napi::Symbol::New(env, "kTestAccessorInternal");
Napi::Symbol kTestMethodInternal = Napi::Symbol::New(env, "kTestMethodInternal");

exports.Set("Test", DefineClass(env, "Test", {
InstanceMethod("test_set_method", &Test::SetMethod),
InstanceMethod("test_get_method", &Test::GetMethod),
InstanceMethod(Napi::Symbol::WellKnown(env, "iterator"), &Test::Iter),
InstanceAccessor("test_getter_only", &Test::Getter, nullptr),
InstanceAccessor("test_setter_only", nullptr, &Test::Setter),
InstanceAccessor("test_getter_setter", &Test::Getter, &Test::Setter),

// expose symbols for testing
StaticValue("kTestStaticValueInternal", kTestStaticValueInternal),
StaticValue("kTestStaticAccessorInternal", kTestStaticAccessorInternal),
StaticValue("kTestStaticMethodInternal", kTestStaticMethodInternal),
StaticValue("kTestValueInternal", kTestValueInternal),
StaticValue("kTestAccessorInternal", kTestAccessorInternal),
StaticValue("kTestMethodInternal", kTestMethodInternal),

// test data
StaticValue("testStaticValue", Napi::String::New(env, "value"), napi_enumerable),
StaticValue(kTestStaticValueInternal, Napi::Number::New(env, 5), napi_default),

StaticAccessor("testStaticGetter", &StaticGetter, nullptr, napi_enumerable),
StaticAccessor("testStaticSetter", nullptr, &StaticSetter, napi_default),
StaticAccessor("testStaticGetSet", &StaticGetter, &StaticSetter, napi_enumerable),
StaticAccessor(kTestStaticAccessorInternal, &StaticGetter, &StaticSetter, napi_enumerable),

StaticMethod("testStaticMethod", &TestStaticMethod, napi_enumerable),
StaticMethod(kTestStaticMethodInternal, &TestStaticMethodInternal, napi_default),

InstanceValue("testValue", Napi::Boolean::New(env, true), napi_enumerable),
InstanceValue(kTestValueInternal, Napi::Boolean::New(env, false), napi_enumerable),

InstanceAccessor("testGetter", &Test::Getter, nullptr, napi_enumerable),
InstanceAccessor("testSetter", nullptr, &Test::Setter, napi_default),
InstanceAccessor("testGetSet", &Test::Getter, &Test::Setter, napi_enumerable),
InstanceAccessor(kTestAccessorInternal, &Test::Getter, &Test::Setter, napi_enumerable),

InstanceMethod("testMethod", &Test::TestMethod, napi_enumerable),
InstanceMethod(kTestMethodInternal, &Test::TestMethodInternal, napi_default),

// conventions
InstanceAccessor(Napi::Symbol::WellKnown(env, "toStringTag"), &Test::ToStringTag, nullptr, napi_enumerable),
InstanceMethod(Napi::Symbol::WellKnown(env, "iterator"), &Test::Iterator, napi_default),

}));
}

private:
uint32_t value;
Napi::FunctionReference Constructor;
std::string value_;
};

Napi::Object InitObjectWrap(Napi::Env env) {
testStaticContextRef = Napi::Persistent(Napi::Object::New(env));
testStaticContextRef.SuppressDestruct();

Napi::Object exports = Napi::Object::New(env);
Test::Initialize(env, exports);
return exports;
Expand Down
Loading

0 comments on commit 2bd929a

Please sign in to comment.