blob: e74b14b2ceb3e820a5c6c77c79ec8718dc776bb9 [file] [log] [blame]
/* ObjectReference can be used to create references to Values that
are not Objects by creating a blank Object and setting Values to
it. Subclasses of Objects can only be set using an ObjectReference
by first casting it as an Object. */
#include "assert.h"
#include "napi.h"
#include "test_helper.h"
using namespace Napi;
ObjectReference weak;
ObjectReference persistent;
ObjectReference reference;
ObjectReference casted_weak;
ObjectReference casted_persistent;
ObjectReference casted_reference;
// Set keys can be one of:
// C style string, std::string& utf8, and const char *
// Set values can be one of:
// Napi::Value
// napi_value (req static_cast)
// const char* (c style string)
// boolean
// double
enum VAL_TYPES { JS = 0, C_STR, CPP_STR, BOOL, INT, DOUBLE, JS_CAST };
void MoveOperatorsTest(const Napi::CallbackInfo& info) {
Napi::ObjectReference existingRef;
Napi::ObjectReference existingRef2;
Napi::Object testObject = Napi::Object::New(info.Env());
testObject.Set("testProp", "tProp");
// ObjectReference(Reference<Object>&& other);
Napi::Reference<Napi::Object> refObj =
Napi::Reference<Napi::Object>::New(testObject);
Napi::ObjectReference objRef = std::move(refObj);
std::string prop = MaybeUnwrap(objRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");
// ObjectReference& operator=(Reference<Object>&& other);
Napi::Reference<Napi::Object> refObj2 =
Napi::Reference<Napi::Object>::New(testObject);
existingRef = std::move(refObj2);
prop = MaybeUnwrap(existingRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");
// ObjectReference(ObjectReference&& other);
Napi::ObjectReference objRef3 = std::move(existingRef);
prop = MaybeUnwrap(objRef3.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");
// ObjectReference& operator=(ObjectReference&& other);
existingRef2 = std::move(objRef3);
prop = MaybeUnwrap(objRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");
}
void SetObjectWithCStringKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
std::string c_key = key.As<Napi::String>().Utf8Value();
switch (valType) {
case JS:
obj.Set(c_key.c_str(), val);
break;
case JS_CAST:
obj.Set(c_key.c_str(), static_cast<napi_value>(val));
break;
case C_STR: {
std::string c_val = val.As<Napi::String>().Utf8Value();
obj.Set(c_key.c_str(), c_val.c_str());
break;
}
case BOOL:
obj.Set(c_key.c_str(), val.As<Napi::Boolean>().Value());
break;
case DOUBLE:
obj.Set(c_key.c_str(), val.As<Napi::Number>().DoubleValue());
break;
}
}
void SetObjectWithCppStringKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
std::string c_key = key.As<Napi::String>();
switch (valType) {
case JS:
obj.Set(c_key, val);
break;
case JS_CAST:
obj.Set(c_key, static_cast<napi_value>(val));
break;
case CPP_STR: {
std::string c_val = val.As<Napi::String>();
obj.Set(c_key, c_val);
break;
}
case BOOL:
obj.Set(c_key, val.As<Napi::Boolean>().Value());
break;
case DOUBLE:
obj.Set(c_key, val.As<Napi::Number>().DoubleValue());
break;
}
}
void SetObjectWithIntKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
uint32_t c_key = key.As<Napi::Number>().Uint32Value();
switch (valType) {
case JS:
obj.Set(c_key, val);
break;
case JS_CAST:
obj.Set(c_key, static_cast<napi_value>(val));
break;
case C_STR: {
std::string c_val = val.As<Napi::String>();
obj.Set(c_key, c_val.c_str());
break;
}
case CPP_STR: {
std::string cpp_val = val.As<Napi::String>();
obj.Set(c_key, cpp_val);
break;
}
case BOOL:
obj.Set(c_key, val.As<Napi::Boolean>().Value());
break;
case DOUBLE:
obj.Set(c_key, val.As<Napi::Number>().DoubleValue());
break;
}
}
void SetObject(const Napi::CallbackInfo& info) {
Env env = info.Env();
HandleScope scope(env);
weak = Weak(Object::New(env));
weak.SuppressDestruct();
persistent = Persistent(Object::New(env));
persistent.SuppressDestruct();
reference = Reference<Object>::New(Object::New(env), 2);
reference.SuppressDestruct();
Napi::Object configObject = info[0].As<Napi::Object>();
int keyType =
MaybeUnwrap(configObject.Get("keyType")).As<Napi::Number>().Uint32Value();
int valType =
MaybeUnwrap(configObject.Get("valType")).As<Napi::Number>().Uint32Value();
Napi::Value key = MaybeUnwrap(configObject.Get("key"));
Napi::Value val = MaybeUnwrap(configObject.Get("val"));
switch (keyType) {
case CPP_STR:
SetObjectWithCppStringKey(weak, key, val, valType);
SetObjectWithCppStringKey(persistent, key, val, valType);
SetObjectWithCppStringKey(reference, key, val, valType);
break;
case C_STR:
SetObjectWithCStringKey(weak, key, val, valType);
SetObjectWithCStringKey(persistent, key, val, valType);
SetObjectWithCStringKey(reference, key, val, valType);
break;
case INT:
SetObjectWithIntKey(weak, key, val, valType);
SetObjectWithIntKey(persistent, key, val, valType);
SetObjectWithIntKey(reference, key, val, valType);
default:
break;
}
}
void SetCastedObjects(const CallbackInfo& info) {
Env env = info.Env();
HandleScope scope(env);
Array ex = Array::New(env);
ex.Set((uint32_t)0, String::New(env, "hello"));
ex.Set(1, String::New(env, "world"));
ex.Set(2, String::New(env, "!"));
casted_weak = Weak(ex.As<Object>());
casted_weak.SuppressDestruct();
casted_persistent = Persistent(ex.As<Object>());
casted_persistent.SuppressDestruct();
casted_reference = Reference<Object>::New(ex.As<Object>(), 2);
casted_reference.SuppressDestruct();
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Value GetFromValue(const CallbackInfo& info) {
Env env = info.Env();
if (info[0] == String::New(env, "weak")) {
if (weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return weak.Value();
}
} else if (info[0] == String::New(env, "persistent")) {
return persistent.Value();
} else {
return reference.Value();
}
}
Value GetHelper(ObjectReference& ref,
Object& configObject,
const Napi::Env& env) {
int keyType =
MaybeUnwrap(configObject.Get("keyType")).As<Napi::Number>().Uint32Value();
if (ref.IsEmpty()) {
return String::New(env, "No referenced Value");
}
switch (keyType) {
case C_STR: {
std::string c_key =
MaybeUnwrap(configObject.Get("key")).As<String>().Utf8Value();
return MaybeUnwrap(ref.Get(c_key.c_str()));
break;
}
case CPP_STR: {
std::string cpp_key =
MaybeUnwrap(configObject.Get("key")).As<String>().Utf8Value();
return MaybeUnwrap(ref.Get(cpp_key));
break;
}
case INT: {
uint32_t key =
MaybeUnwrap(configObject.Get("key")).As<Number>().Uint32Value();
return MaybeUnwrap(ref.Get(key));
break;
}
default:
return String::New(env, "Error: Reached end of getter");
break;
}
}
Value GetFromGetters(const CallbackInfo& info) {
std::string object_req = info[0].As<String>();
Object configObject = info[1].As<Object>();
if (object_req == "weak") {
return GetHelper(weak, configObject, info.Env());
} else if (object_req == "persistent") {
return GetHelper(persistent, configObject, info.Env());
}
return GetHelper(reference, configObject, info.Env());
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
// info[1] is the key, and it be either a String or a Number.
Value GetFromGetter(const CallbackInfo& info) {
Env env = info.Env();
if (info[0] == String::New(env, "weak")) {
if (weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
if (info[1].IsString()) {
return MaybeUnwrap(weak.Get(info[1].As<String>().Utf8Value()));
} else if (info[1].IsNumber()) {
return MaybeUnwrap(weak.Get(info[1].As<Number>().Uint32Value()));
}
}
} else if (info[0] == String::New(env, "persistent")) {
if (info[1].IsString()) {
return MaybeUnwrap(persistent.Get(info[1].As<String>().Utf8Value()));
} else if (info[1].IsNumber()) {
return MaybeUnwrap(persistent.Get(info[1].As<Number>().Uint32Value()));
}
} else {
if (info[0].IsString()) {
return MaybeUnwrap(reference.Get(info[0].As<String>().Utf8Value()));
} else if (info[0].IsNumber()) {
return MaybeUnwrap(reference.Get(info[0].As<Number>().Uint32Value()));
}
}
return String::New(env, "Error: Reached end of getter");
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Value GetCastedFromValue(const CallbackInfo& info) {
Env env = info.Env();
if (info[0] == String::New(env, "weak")) {
if (casted_weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return casted_weak.Value();
}
} else if (info[0] == String::New(env, "persistent")) {
return casted_persistent.Value();
} else {
return casted_reference.Value();
}
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
// info[1] is the key and it must be a Number.
Value GetCastedFromGetter(const CallbackInfo& info) {
Env env = info.Env();
if (info[0] == String::New(env, "weak")) {
if (casted_weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return MaybeUnwrap(casted_weak.Get(info[1].As<Number>()));
}
} else if (info[0] == String::New(env, "persistent")) {
return MaybeUnwrap(casted_persistent.Get(info[1].As<Number>()));
} else {
return MaybeUnwrap(casted_reference.Get(info[1].As<Number>()));
}
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Number UnrefObjects(const CallbackInfo& info) {
Env env = info.Env();
uint32_t num;
if (info[0] == String::New(env, "weak")) {
num = weak.Unref();
} else if (info[0] == String::New(env, "persistent")) {
num = persistent.Unref();
} else if (info[0] == String::New(env, "references")) {
num = reference.Unref();
} else if (info[0] == String::New(env, "casted weak")) {
num = casted_weak.Unref();
} else if (info[0] == String::New(env, "casted persistent")) {
num = casted_persistent.Unref();
} else {
num = casted_reference.Unref();
}
return Number::New(env, num);
}
// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Number RefObjects(const CallbackInfo& info) {
Env env = info.Env();
uint32_t num;
if (info[0] == String::New(env, "weak")) {
num = weak.Ref();
} else if (info[0] == String::New(env, "persistent")) {
num = persistent.Ref();
} else if (info[0] == String::New(env, "references")) {
num = reference.Ref();
} else if (info[0] == String::New(env, "casted weak")) {
num = casted_weak.Ref();
} else if (info[0] == String::New(env, "casted persistent")) {
num = casted_persistent.Ref();
} else {
num = casted_reference.Ref();
}
return Number::New(env, num);
}
Object InitObjectReference(Env env) {
Object exports = Object::New(env);
exports["setCastedObjects"] = Function::New(env, SetCastedObjects);
exports["setObject"] = Function::New(env, SetObject);
exports["getCastedFromValue"] = Function::New(env, GetCastedFromValue);
exports["getFromGetters"] = Function::New(env, GetFromGetters);
exports["getCastedFromGetter"] = Function::New(env, GetCastedFromGetter);
exports["getFromValue"] = Function::New(env, GetFromValue);
exports["unrefObjects"] = Function::New(env, UnrefObjects);
exports["refObjects"] = Function::New(env, RefObjects);
exports["moveOpTest"] = Function::New(env, MoveOperatorsTest);
return exports;
}