| /* 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; |
| } |