diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..1368d5d5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,26 @@ +# Config for clang-format version 16 + +# Standard +BasedOnStyle: llvm +Standard: c++14 + +# Indentation +IndentWidth: 2 +ColumnLimit: 100 + +# Includes +SortIncludes: true +SortUsingDeclarations: true + +# Pointer and reference alignment +PointerAlignment: Left +ReferenceAlignment: Left +ReflowComments: true + +# Line breaking options +BreakBeforeBraces: Attach +BreakConstructorInitializers: BeforeColon +AllowShortFunctionsOnASingleLine: Empty +IndentCaseLabels: true +NamespaceIndentation: Inner + diff --git a/.github/workflows/validate-cpp.yml b/.github/workflows/validate-cpp.yml index 47df759a..2dac66eb 100644 --- a/.github/workflows/validate-cpp.yml +++ b/.github/workflows/validate-cpp.yml @@ -7,31 +7,30 @@ on: paths: - '.github/workflows/validate-cpp.yml' - 'cpp/**' - - 'MMKV/**' - 'android/src/main/cpp/**' + - 'ios/**' pull_request: paths: - '.github/workflows/validate-cpp.yml' - 'cpp/**' - - 'MMKV/**' - 'android/src/main/cpp/**' + - 'ios/**' jobs: lint: - name: cpplint + name: Check clang-format runs-on: ubuntu-latest + strategy: + matrix: + path: + - 'cpp' + - 'android/src/main/cpp' + - 'ios' steps: - uses: actions/checkout@v2 - - uses: reviewdog/action-cpplint@master + - name: Run clang-format style check + uses: jidicula/clang-format-action@v4.11.0 with: - github_token: ${{ secrets.github_token }} - reporter: github-pr-review - flags: --linelength=230 - targets: --recursive cpp android/src/main/cpp - filter: "-legal/copyright\ - ,-readability/todo\ - ,-build/namespaces\ - ,-whitespace/comments\ - ,-runtime/references\ - ,-build/include_order\ - " + clang-format-version: '16' + check-path: ${{ matrix.path }} + diff --git a/android/src/main/cpp/MmkvHostObject.cpp b/android/src/main/cpp/MmkvHostObject.cpp index e059aaee..3d715d02 100644 --- a/android/src/main/cpp/MmkvHostObject.cpp +++ b/android/src/main/cpp/MmkvHostObject.cpp @@ -13,12 +13,15 @@ #include #include -MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey) { - __android_log_print(ANDROID_LOG_INFO, "RNMMKV", "Creating MMKV instance \"%s\"... (Path: %s, Encryption-Key: %s)", +MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path, + std::string cryptKey) { + __android_log_print(ANDROID_LOG_INFO, "RNMMKV", + "Creating MMKV instance \"%s\"... (Path: %s, Encryption-Key: %s)", instanceId.c_str(), path.c_str(), cryptKey.c_str()); std::string* pathPtr = path.size() > 0 ? &path : nullptr; std::string* cryptKeyPtr = cryptKey.size() > 0 ? &cryptKey : nullptr; - instance = MMKV::mmkvWithID(instanceId, mmkv::DEFAULT_MMAP_SIZE, MMKV_SINGLE_PROCESS, cryptKeyPtr, pathPtr); + instance = MMKV::mmkvWithID(instanceId, mmkv::DEFAULT_MMAP_SIZE, MMKV_SINGLE_PROCESS, cryptKeyPtr, + pathPtr); if (instance == nullptr) { // Check if instanceId is invalid @@ -28,7 +31,8 @@ MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path, // Check if encryptionKey is invalid if (cryptKey.size() > 16) { - throw std::runtime_error("Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!"); + throw std::runtime_error( + "Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!"); } throw std::runtime_error("Failed to create MMKV instance!"); @@ -56,247 +60,229 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro if (propName == "set") { // MMKV.set(key: string, value: string | number | bool | Uint8Array) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 2, // key, value - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "MMKV::set: First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 2, // key, value + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, + "MMKV::set: First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); + auto keyName = arguments[0].getString(runtime).utf8(runtime); - if (arguments[1].isBool()) { - // bool - instance->set(arguments[1].getBool(), keyName); - } else if (arguments[1].isNumber()) { - // number - instance->set(arguments[1].getNumber(), keyName); - } else if (arguments[1].isString()) { - // string - auto stringValue = arguments[1].getString(runtime).utf8(runtime); - instance->set(stringValue, keyName); - } else if (arguments[1].isObject()) { - // object - auto object = arguments[1].asObject(runtime); - if (isTypedArray(runtime, object)) { - // Uint8Array - auto typedArray = getTypedArray(runtime, object); - auto bufferValue = typedArray.getBuffer(runtime); - mmkv::MMBuffer buffer(bufferValue.data(runtime), - bufferValue.size(runtime), - mmkv::MMBufferCopyFlag::MMBufferNoCopy); - instance->set(buffer, keyName); - } else { - // unknown object - throw jsi::JSError(runtime, "MMKV::set: 'value' argument is an object, but not of type Uint8Array!"); - } - } else { - // unknown type - throw jsi::JSError(runtime, "MMKV::set: 'value' argument is not of type bool, number, string or buffer!"); - } + if (arguments[1].isBool()) { + // bool + instance->set(arguments[1].getBool(), keyName); + } else if (arguments[1].isNumber()) { + // number + instance->set(arguments[1].getNumber(), keyName); + } else if (arguments[1].isString()) { + // string + auto stringValue = arguments[1].getString(runtime).utf8(runtime); + instance->set(stringValue, keyName); + } else if (arguments[1].isObject()) { + // object + auto object = arguments[1].asObject(runtime); + if (isTypedArray(runtime, object)) { + // Uint8Array + auto typedArray = getTypedArray(runtime, object); + auto bufferValue = typedArray.getBuffer(runtime); + mmkv::MMBuffer buffer(bufferValue.data(runtime), bufferValue.size(runtime), + mmkv::MMBufferCopyFlag::MMBufferNoCopy); + instance->set(buffer, keyName); + } else { + // unknown object + throw jsi::JSError( + runtime, "MMKV::set: 'value' argument is an object, but not of type Uint8Array!"); + } + } else { + // unknown type + throw jsi::JSError( + runtime, + "MMKV::set: 'value' argument is not of type bool, number, string or buffer!"); + } - return jsi::Value::undefined(); - }); + return jsi::Value::undefined(); + }); } if (propName == "getBoolean") { // MMKV.getBoolean(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); - bool hasValue; - auto value = instance->getBool(keyName, false, &hasValue); - if (hasValue) { - return jsi::Value(value); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = arguments[0].getString(runtime).utf8(runtime); + bool hasValue; + auto value = instance->getBool(keyName, false, &hasValue); + if (hasValue) { + return jsi::Value(value); + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "getString") { // MMKV.getString(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); - std::string result; - bool hasValue = instance->getString(keyName, result); - if (hasValue) { - return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result)); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = arguments[0].getString(runtime).utf8(runtime); + std::string result; + bool hasValue = instance->getString(keyName, result); + if (hasValue) { + return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result)); + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "getNumber") { // MMKV.getNumber(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); - bool hasValue; - auto value = instance->getDouble(keyName, 0.0, &hasValue); - if (hasValue) { - return jsi::Value(value); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = arguments[0].getString(runtime).utf8(runtime); + bool hasValue; + auto value = instance->getDouble(keyName, 0.0, &hasValue); + if (hasValue) { + return jsi::Value(value); + } else { + return jsi::Value::undefined(); + } + }); } + if (propName == "getBuffer") { + // MMKV.getBuffer(key: string) + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - if (propName == "getBuffer") { - // MMKV.getBuffer(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } - - auto keyName = arguments[0].getString(runtime).utf8(runtime); - mmkv::MMBuffer buffer; - bool hasValue = instance->getBytes(keyName, buffer); - if (hasValue) { - auto length = buffer.length(); - TypedArray array(runtime, length); - auto data = static_cast(buffer.getPtr()); - std::vector vector(length); - vector.assign(data, data + length); - array.update(runtime, vector); - return array; - } else { - return jsi::Value::undefined(); - } - }); - } + auto keyName = arguments[0].getString(runtime).utf8(runtime); + mmkv::MMBuffer buffer; + bool hasValue = instance->getBytes(keyName, buffer); + if (hasValue) { + auto length = buffer.length(); + TypedArray array(runtime, length); + auto data = static_cast(buffer.getPtr()); + std::vector vector(length); + vector.assign(data, data + length); + array.update(runtime, vector); + return array; + } else { + return jsi::Value::undefined(); + } + }); + } if (propName == "contains") { // MMKV.contains(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); - bool containsKey = instance->containsKey(keyName); - return jsi::Value(containsKey); - }); + auto keyName = arguments[0].getString(runtime).utf8(runtime); + bool containsKey = instance->containsKey(keyName); + return jsi::Value(containsKey); + }); } if (propName == "delete") { // MMKV.delete(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = arguments[0].getString(runtime).utf8(runtime); - instance->removeValueForKey(keyName); - return jsi::Value::undefined(); - }); + auto keyName = arguments[0].getString(runtime).utf8(runtime); + instance->removeValueForKey(keyName); + return jsi::Value::undefined(); + }); } if (propName == "getAllKeys") { // MMKV.getAllKeys() - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 0, - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - auto keys = instance->allKeys(); - auto array = jsi::Array(runtime, keys.size()); - for (int i = 0; i < keys.size(); i++) { - array.setValueAtIndex(runtime, i, keys[i]); - } - return array; - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), 0, + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + auto keys = instance->allKeys(); + auto array = jsi::Array(runtime, keys.size()); + for (int i = 0; i < keys.size(); i++) { + array.setValueAtIndex(runtime, i, keys[i]); + } + return array; + }); } if (propName == "clearAll") { // MMKV.clearAll() - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 0, - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - instance->clearAll(); - return jsi::Value::undefined(); - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), 0, + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + instance->clearAll(); + return jsi::Value::undefined(); + }); } if (propName == "recrypt") { // MMKV.recrypt(encryptionKey) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // encryptionKey - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (arguments[0].isUndefined()) { - // reset encryption key to "no encryption" - instance->reKey(std::string()); - } else if (arguments[0].isString()) { - // reKey(..) with new encryption-key - auto encryptionKey = arguments[0].getString(runtime).utf8(runtime); - instance->reKey(encryptionKey); - } else { - throw jsi::JSError(runtime, "First argument ('encryptionKey') has to be of type string (or undefined)!"); - } - return jsi::Value::undefined(); - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // encryptionKey + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (arguments[0].isUndefined()) { + // reset encryption key to "no encryption" + instance->reKey(std::string()); + } else if (arguments[0].isString()) { + // reKey(..) with new encryption-key + auto encryptionKey = arguments[0].getString(runtime).utf8(runtime); + instance->reKey(encryptionKey); + } else { + throw jsi::JSError( + runtime, + "First argument ('encryptionKey') has to be of type string (or undefined)!"); + } + return jsi::Value::undefined(); + }); } return jsi::Value::undefined(); diff --git a/android/src/main/cpp/MmkvHostObject.h b/android/src/main/cpp/MmkvHostObject.h index 3f0079ed..b2c5573a 100644 --- a/android/src/main/cpp/MmkvHostObject.h +++ b/android/src/main/cpp/MmkvHostObject.h @@ -8,12 +8,12 @@ #pragma once -#include #include +#include using namespace facebook; -class JSI_EXPORT MmkvHostObject: public jsi::HostObject { +class JSI_EXPORT MmkvHostObject : public jsi::HostObject { public: MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey); diff --git a/android/src/main/cpp/cpp-adapter.cpp b/android/src/main/cpp/cpp-adapter.cpp index 4ac359f2..cf167c9d 100644 --- a/android/src/main/cpp/cpp-adapter.cpp +++ b/android/src/main/cpp/cpp-adapter.cpp @@ -1,70 +1,77 @@ -#include -#include -#include #include "MmkvHostObject.h" #include "TypedArray.h" +#include +#include +#include using namespace facebook; -std::string getPropertyAsStringOrEmptyFromObject(jsi::Object& object, const std::string& propertyName, jsi::Runtime& runtime) { - jsi::Value value = object.getProperty(runtime, propertyName.c_str()); - return value.isString() ? value.asString(runtime).utf8(runtime) : ""; +std::string getPropertyAsStringOrEmptyFromObject(jsi::Object& object, + const std::string& propertyName, + jsi::Runtime& runtime) { + jsi::Value value = object.getProperty(runtime, propertyName.c_str()); + return value.isString() ? value.asString(runtime).utf8(runtime) : ""; } void install(jsi::Runtime& jsiRuntime) { - // MMKV.createNewInstance() - auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(jsiRuntime, - jsi::PropNameID::forAscii(jsiRuntime, "mmkvCreateNewInstance"), - 1, - [](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (count != 1) { - throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!"); - } - jsi::Object config = arguments[0].asObject(runtime); + // MMKV.createNewInstance() + auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction( + jsiRuntime, jsi::PropNameID::forAscii(jsiRuntime, "mmkvCreateNewInstance"), 1, + [](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (count != 1) { + throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!"); + } + jsi::Object config = arguments[0].asObject(runtime); - std::string instanceId = getPropertyAsStringOrEmptyFromObject(config, "id", runtime); - std::string path = getPropertyAsStringOrEmptyFromObject(config, "path", runtime); - std::string encryptionKey = getPropertyAsStringOrEmptyFromObject(config, "encryptionKey", runtime); + std::string instanceId = getPropertyAsStringOrEmptyFromObject(config, "id", runtime); + std::string path = getPropertyAsStringOrEmptyFromObject(config, "path", runtime); + std::string encryptionKey = + getPropertyAsStringOrEmptyFromObject(config, "encryptionKey", runtime); - auto instance = std::make_shared(instanceId, path, encryptionKey); - return jsi::Object::createFromHostObject(runtime, instance); - }); - jsiRuntime.global().setProperty(jsiRuntime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance)); + auto instance = std::make_shared(instanceId, path, encryptionKey); + return jsi::Object::createFromHostObject(runtime, instance); + }); + jsiRuntime.global().setProperty(jsiRuntime, "mmkvCreateNewInstance", + std::move(mmkvCreateNewInstance)); - // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets destroyed and the cache gets invalidated. - auto propNameIdCache = std::make_shared(jsiRuntime); - jsiRuntime.global().setProperty(jsiRuntime, "mmkvArrayBufferPropNameIdCache", jsi::Object::createFromHostObject(jsiRuntime, propNameIdCache)); + // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets + // destroyed and the cache gets invalidated. + auto propNameIdCache = std::make_shared(jsiRuntime); + jsiRuntime.global().setProperty(jsiRuntime, "mmkvArrayBufferPropNameIdCache", + jsi::Object::createFromHostObject(jsiRuntime, propNameIdCache)); } -std::string jstringToStdString(JNIEnv *env, jstring jStr) { - if (!jStr) return ""; +std::string jstringToStdString(JNIEnv* env, jstring jStr) { + if (!jStr) + return ""; - const auto stringClass = env->GetObjectClass(jStr); - const auto getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); - const auto stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8")); + const auto stringClass = env->GetObjectClass(jStr); + const auto getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); + const auto stringJbytes = + (jbyteArray)env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8")); - auto length = (size_t) env->GetArrayLength(stringJbytes); - auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr); + auto length = (size_t)env->GetArrayLength(stringJbytes); + auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr); - std::string ret = std::string((char *)pBytes, length); - env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT); + std::string ret = std::string((char*)pBytes, length); + env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT); - env->DeleteLocalRef(stringJbytes); - env->DeleteLocalRef(stringClass); - return ret; + env->DeleteLocalRef(stringJbytes); + env->DeleteLocalRef(stringClass); + return ret; } -extern "C" -JNIEXPORT void JNICALL -Java_com_reactnativemmkv_MmkvModule_nativeInstall(JNIEnv *env, jobject clazz, jlong jsiPtr, jstring path) { - MMKV::initializeMMKV(jstringToStdString(env, path)); +extern "C" JNIEXPORT void JNICALL Java_com_reactnativemmkv_MmkvModule_nativeInstall(JNIEnv* env, + jobject clazz, + jlong jsiPtr, + jstring path) { + MMKV::initializeMMKV(jstringToStdString(env, path)); - auto runtime = reinterpret_cast(jsiPtr); - if (runtime) { - install(*runtime); - } - // if runtime was nullptr, MMKV will not be installed. This should only happen while Remote Debugging (Chrome), but will be weird either way. + auto runtime = reinterpret_cast(jsiPtr); + if (runtime) { + install(*runtime); + } + // if runtime was nullptr, MMKV will not be installed. This should only happen while Remote + // Debugging (Chrome), but will be weird either way. } diff --git a/cpp/TypedArray.cpp b/cpp/TypedArray.cpp index d3c0f6e7..5ad11ee6 100644 --- a/cpp/TypedArray.cpp +++ b/cpp/TypedArray.cpp @@ -8,40 +8,39 @@ #include "TypedArray.h" -#include +#include #include +#include +#include #include #include -#include -#include -template -using ContentType = typename typedArrayTypeMap::type; +template using ContentType = typename typedArrayTypeMap::type; enum class Prop { - Buffer, // "buffer" - Constructor, // "constructor" - Name, // "name" - Proto, // "__proto__" - Length, // "length" - ByteLength, // "byteLength" - ByteOffset, // "offset" - IsView, // "isView" - ArrayBuffer, // "ArrayBuffer" - Int8Array, // "Int8Array" - Int16Array, // "Int16Array" - Int32Array, // "Int32Array" - Uint8Array, // "Uint8Array" + Buffer, // "buffer" + Constructor, // "constructor" + Name, // "name" + Proto, // "__proto__" + Length, // "length" + ByteLength, // "byteLength" + ByteOffset, // "offset" + IsView, // "isView" + ArrayBuffer, // "ArrayBuffer" + Int8Array, // "Int8Array" + Int16Array, // "Int16Array" + Int32Array, // "Int32Array" + Uint8Array, // "Uint8Array" Uint8ClampedArray, // "Uint8ClampedArray" - Uint16Array, // "Uint16Array" - Uint32Array, // "Uint32Array" - Float32Array, // "Float32Array" - Float64Array, // "Float64Array" + Uint16Array, // "Uint16Array" + Uint32Array, // "Uint32Array" + Float32Array, // "Float32Array" + Float64Array, // "Float64Array" }; class PropNameIDCache { - public: - const jsi::PropNameID &get(jsi::Runtime &runtime, Prop prop) { +public: + const jsi::PropNameID& get(jsi::Runtime& runtime, Prop prop) { auto key = reinterpret_cast(&runtime); if (this->props.find(key) == this->props.end()) { this->props[key] = std::unordered_map>(); @@ -52,7 +51,7 @@ class PropNameIDCache { return *(this->props[key][prop]); } - const jsi::PropNameID &getConstructorNameProp(jsi::Runtime &runtime, TypedArrayKind kind); + const jsi::PropNameID& getConstructorNameProp(jsi::Runtime& runtime, TypedArrayKind kind); void invalidate(uintptr_t key) { if (props.find(key) != props.end()) { @@ -60,37 +59,36 @@ class PropNameIDCache { } } - private: +private: std::unordered_map>> props; - jsi::PropNameID createProp(jsi::Runtime &runtime, Prop prop); + jsi::PropNameID createProp(jsi::Runtime& runtime, Prop prop); }; PropNameIDCache propNameIDCache; -InvalidateCacheOnDestroy::InvalidateCacheOnDestroy(jsi::Runtime &runtime) { +InvalidateCacheOnDestroy::InvalidateCacheOnDestroy(jsi::Runtime& runtime) { key = reinterpret_cast(&runtime); } InvalidateCacheOnDestroy::~InvalidateCacheOnDestroy() { propNameIDCache.invalidate(key); } -TypedArrayKind getTypedArrayKindForName(const std::string &name); +TypedArrayKind getTypedArrayKindForName(const std::string& name); -TypedArrayBase::TypedArrayBase(jsi::Runtime &runtime, size_t size, TypedArrayKind kind) +TypedArrayBase::TypedArrayBase(jsi::Runtime& runtime, size_t size, TypedArrayKind kind) : TypedArrayBase( - runtime, - runtime.global() - .getProperty(runtime, propNameIDCache.getConstructorNameProp(runtime, kind)) - .asObject(runtime) - .asFunction(runtime) - .callAsConstructor(runtime, {static_cast(size)}) - .asObject(runtime)) {} - -TypedArrayBase::TypedArrayBase(jsi::Runtime &runtime, const jsi::Object &obj) + runtime, runtime.global() + .getProperty(runtime, propNameIDCache.getConstructorNameProp(runtime, kind)) + .asObject(runtime) + .asFunction(runtime) + .callAsConstructor(runtime, {static_cast(size)}) + .asObject(runtime)) {} + +TypedArrayBase::TypedArrayBase(jsi::Runtime& runtime, const jsi::Object& obj) : jsi::Object(jsi::Value(runtime, obj).asObject(runtime)) {} -TypedArrayKind TypedArrayBase::getKind(jsi::Runtime &runtime) const { +TypedArrayKind TypedArrayBase::getKind(jsi::Runtime& runtime) const { auto constructorName = this->getProperty(runtime, propNameIDCache.get(runtime, Prop::Constructor)) .asObject(runtime) .getProperty(runtime, propNameIDCache.get(runtime, Prop::Name)) @@ -99,34 +97,34 @@ TypedArrayKind TypedArrayBase::getKind(jsi::Runtime &runtime) const { return getTypedArrayKindForName(constructorName); } -size_t TypedArrayBase::size(jsi::Runtime &runtime) const { +size_t TypedArrayBase::size(jsi::Runtime& runtime) const { return getProperty(runtime, propNameIDCache.get(runtime, Prop::Length)).asNumber(); } -size_t TypedArrayBase::length(jsi::Runtime &runtime) const { +size_t TypedArrayBase::length(jsi::Runtime& runtime) const { return getProperty(runtime, propNameIDCache.get(runtime, Prop::Length)).asNumber(); } -size_t TypedArrayBase::byteLength(jsi::Runtime &runtime) const { +size_t TypedArrayBase::byteLength(jsi::Runtime& runtime) const { return getProperty(runtime, propNameIDCache.get(runtime, Prop::ByteLength)).asNumber(); } -size_t TypedArrayBase::byteOffset(jsi::Runtime &runtime) const { +size_t TypedArrayBase::byteOffset(jsi::Runtime& runtime) const { return getProperty(runtime, propNameIDCache.get(runtime, Prop::ByteOffset)).asNumber(); } -bool TypedArrayBase::hasBuffer(jsi::Runtime &runtime) const { +bool TypedArrayBase::hasBuffer(jsi::Runtime& runtime) const { auto buffer = getProperty(runtime, propNameIDCache.get(runtime, Prop::Buffer)); return buffer.isObject() && buffer.asObject(runtime).isArrayBuffer(runtime); } -std::vector TypedArrayBase::toVector(jsi::Runtime &runtime) { - auto start = reinterpret_cast(getBuffer(runtime).data(runtime) + byteOffset(runtime)); +std::vector TypedArrayBase::toVector(jsi::Runtime& runtime) { + auto start = reinterpret_cast(getBuffer(runtime).data(runtime) + byteOffset(runtime)); auto end = start + byteLength(runtime); return std::vector(start, end); } -jsi::ArrayBuffer TypedArrayBase::getBuffer(jsi::Runtime &runtime) const { +jsi::ArrayBuffer TypedArrayBase::getBuffer(jsi::Runtime& runtime) const { auto buffer = getProperty(runtime, propNameIDCache.get(runtime, Prop::Buffer)); if (buffer.isObject() && buffer.asObject(runtime).isArrayBuffer(runtime)) { return buffer.asObject(runtime).getArrayBuffer(runtime); @@ -135,7 +133,7 @@ jsi::ArrayBuffer TypedArrayBase::getBuffer(jsi::Runtime &runtime) const { } } -bool isTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj) { +bool isTypedArray(jsi::Runtime& runtime, const jsi::Object& jsObj) { auto jsVal = runtime.global() .getProperty(runtime, propNameIDCache.get(runtime, Prop::ArrayBuffer)) .asObject(runtime) @@ -150,7 +148,7 @@ bool isTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj) { } } -TypedArrayBase getTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj) { +TypedArrayBase getTypedArray(jsi::Runtime& runtime, const jsi::Object& jsObj) { auto jsVal = runtime.global() .getProperty(runtime, propNameIDCache.get(runtime, Prop::ArrayBuffer)) .asObject(runtime) @@ -165,24 +163,21 @@ TypedArrayBase getTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj) { } } -std::vector arrayBufferToVector(jsi::Runtime &runtime, jsi::Object &jsObj) { +std::vector arrayBufferToVector(jsi::Runtime& runtime, jsi::Object& jsObj) { if (!jsObj.isArrayBuffer(runtime)) { throw std::runtime_error("Object is not an ArrayBuffer"); } auto jsArrayBuffer = jsObj.getArrayBuffer(runtime); - uint8_t *dataBlock = jsArrayBuffer.data(runtime); + uint8_t* dataBlock = jsArrayBuffer.data(runtime); size_t blockSize = jsArrayBuffer.getProperty(runtime, propNameIDCache.get(runtime, Prop::ByteLength)).asNumber(); return std::vector(dataBlock, dataBlock + blockSize); } -void arrayBufferUpdate( - jsi::Runtime &runtime, - jsi::ArrayBuffer &buffer, - std::vector data, - size_t offset) { - uint8_t *dataBlock = buffer.data(runtime); +void arrayBufferUpdate(jsi::Runtime& runtime, jsi::ArrayBuffer& buffer, std::vector data, + size_t offset) { + uint8_t* dataBlock = buffer.data(runtime); size_t blockSize = buffer.size(runtime); if (data.size() > blockSize) { throw jsi::JSError(runtime, "ArrayBuffer is to small to fit data"); @@ -191,51 +186,49 @@ void arrayBufferUpdate( } template -TypedArray::TypedArray(jsi::Runtime &runtime, size_t size) : TypedArrayBase(runtime, size, T) {} +TypedArray::TypedArray(jsi::Runtime& runtime, size_t size) : TypedArrayBase(runtime, size, T) {} template -TypedArray::TypedArray(jsi::Runtime &runtime, std::vector> data) +TypedArray::TypedArray(jsi::Runtime& runtime, std::vector> data) : TypedArrayBase(runtime, data.size(), T) { update(runtime, data); } template -TypedArray::TypedArray(TypedArrayBase &&base) : TypedArrayBase(std::move(base)) {} +TypedArray::TypedArray(TypedArrayBase&& base) : TypedArrayBase(std::move(base)) {} template -std::vector> TypedArray::toVector(jsi::Runtime &runtime) { +std::vector> TypedArray::toVector(jsi::Runtime& runtime) { auto start = - reinterpret_cast *>(getBuffer(runtime).data(runtime) + byteOffset(runtime)); + reinterpret_cast*>(getBuffer(runtime).data(runtime) + byteOffset(runtime)); auto end = start + size(runtime); return std::vector>(start, end); } template -void TypedArray::update(jsi::Runtime &runtime, const std::vector> &data) { +void TypedArray::update(jsi::Runtime& runtime, const std::vector>& data) { if (data.size() != size(runtime)) { throw jsi::JSError(runtime, "TypedArray can only be updated with a vector of the same size"); } - uint8_t *rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime); - std::copy(data.begin(), data.end(), reinterpret_cast *>(rawData)); + uint8_t* rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime); + std::copy(data.begin(), data.end(), reinterpret_cast*>(rawData)); } template -void TypedArray::updateUnsafe(jsi::Runtime &runtime, ContentType *data, size_t length) { +void TypedArray::updateUnsafe(jsi::Runtime& runtime, ContentType* data, size_t length) { if (length != size(runtime)) { throw jsi::JSError(runtime, "TypedArray can only be updated with an array of the same size"); } - uint8_t *rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime); + uint8_t* rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime); memcpy(rawData, data, length); } -template -uint8_t* TypedArray::data(jsi::Runtime &runtime) { +template uint8_t* TypedArray::data(jsi::Runtime& runtime) { return getBuffer(runtime).data(runtime) + byteOffset(runtime); } -const jsi::PropNameID &PropNameIDCache::getConstructorNameProp( - jsi::Runtime &runtime, - TypedArrayKind kind) { +const jsi::PropNameID& PropNameIDCache::getConstructorNameProp(jsi::Runtime& runtime, + TypedArrayKind kind) { switch (kind) { case TypedArrayKind::Int8Array: return get(runtime, Prop::Int8Array); @@ -258,8 +251,8 @@ const jsi::PropNameID &PropNameIDCache::getConstructorNameProp( } } -jsi::PropNameID PropNameIDCache::createProp(jsi::Runtime &runtime, Prop prop) { - auto create = [&](const std::string &propName) { +jsi::PropNameID PropNameIDCache::createProp(jsi::Runtime& runtime, Prop prop) { + auto create = [&](const std::string& propName) { return jsi::PropNameID::forUtf8(runtime, propName); }; switch (prop) { @@ -314,7 +307,7 @@ std::unordered_map nameToKindMap = { {"Float64Array", TypedArrayKind::Float64Array}, }; -TypedArrayKind getTypedArrayKindForName(const std::string &name) { +TypedArrayKind getTypedArrayKindForName(const std::string& name) { return nameToKindMap.at(name); } diff --git a/cpp/TypedArray.h b/cpp/TypedArray.h index 8c1058ec..c58140bc 100644 --- a/cpp/TypedArray.h +++ b/cpp/TypedArray.h @@ -26,45 +26,34 @@ enum class TypedArrayKind { Float64Array, }; -template -class TypedArray; +template class TypedArray; -template -struct typedArrayTypeMap; -template <> -struct typedArrayTypeMap { +template struct typedArrayTypeMap; +template <> struct typedArrayTypeMap { typedef int8_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef int16_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef int32_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef uint8_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef uint8_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef uint16_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef uint32_t type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef float type; }; -template <> -struct typedArrayTypeMap { +template <> struct typedArrayTypeMap { typedef double type; }; @@ -72,105 +61,91 @@ struct typedArrayTypeMap { // Attach this object to global in specific jsi::Runtime to make sure lifecycle of // the cache object is connected to the lifecycle of the js runtime class InvalidateCacheOnDestroy : public jsi::HostObject { - public: - explicit InvalidateCacheOnDestroy(jsi::Runtime &runtime); +public: + explicit InvalidateCacheOnDestroy(jsi::Runtime& runtime); virtual ~InvalidateCacheOnDestroy(); - virtual jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) { + virtual jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) { return jsi::Value::null(); } - virtual void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) {} - virtual std::vector getPropertyNames(jsi::Runtime &rt) { + virtual void set(jsi::Runtime&, const jsi::PropNameID& name, const jsi::Value& value) {} + virtual std::vector getPropertyNames(jsi::Runtime& rt) { return {}; } - private: +private: uintptr_t key; }; class TypedArrayBase : public jsi::Object { - public: - template - using ContentType = typename typedArrayTypeMap::type; - - TypedArrayBase(jsi::Runtime &, size_t, TypedArrayKind); - TypedArrayBase(jsi::Runtime &, const jsi::Object &); - TypedArrayBase(TypedArrayBase &&) = default; - TypedArrayBase &operator=(TypedArrayBase &&) = default; - - TypedArrayKind getKind(jsi::Runtime &runtime) const; - - template - TypedArray get(jsi::Runtime &runtime) const &; - template - TypedArray get(jsi::Runtime &runtime) &&; - template - TypedArray as(jsi::Runtime &runtime) const &; - template - TypedArray as(jsi::Runtime &runtime) &&; - - size_t size(jsi::Runtime &runtime) const; - size_t length(jsi::Runtime &runtime) const; - size_t byteLength(jsi::Runtime &runtime) const; - size_t byteOffset(jsi::Runtime &runtime) const; - bool hasBuffer(jsi::Runtime &runtime) const; - - std::vector toVector(jsi::Runtime &runtime); - jsi::ArrayBuffer getBuffer(jsi::Runtime &runtime) const; - - private: - template - friend class TypedArray; +public: + template using ContentType = typename typedArrayTypeMap::type; + + TypedArrayBase(jsi::Runtime&, size_t, TypedArrayKind); + TypedArrayBase(jsi::Runtime&, const jsi::Object&); + TypedArrayBase(TypedArrayBase&&) = default; + TypedArrayBase& operator=(TypedArrayBase&&) = default; + + TypedArrayKind getKind(jsi::Runtime& runtime) const; + + template TypedArray get(jsi::Runtime& runtime) const&; + template TypedArray get(jsi::Runtime& runtime) &&; + template TypedArray as(jsi::Runtime& runtime) const&; + template TypedArray as(jsi::Runtime& runtime) &&; + + size_t size(jsi::Runtime& runtime) const; + size_t length(jsi::Runtime& runtime) const; + size_t byteLength(jsi::Runtime& runtime) const; + size_t byteOffset(jsi::Runtime& runtime) const; + bool hasBuffer(jsi::Runtime& runtime) const; + + std::vector toVector(jsi::Runtime& runtime); + jsi::ArrayBuffer getBuffer(jsi::Runtime& runtime) const; + +private: + template friend class TypedArray; }; -bool isTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj); -TypedArrayBase getTypedArray(jsi::Runtime &runtime, const jsi::Object &jsObj); - -std::vector arrayBufferToVector(jsi::Runtime &runtime, jsi::Object &jsObj); -void arrayBufferUpdate( - jsi::Runtime &runtime, - jsi::ArrayBuffer &buffer, - std::vector data, - size_t offset); - -template -class TypedArray : public TypedArrayBase { - public: - explicit TypedArray(TypedArrayBase &&base); - TypedArray(jsi::Runtime &runtime, size_t size); - TypedArray(jsi::Runtime &runtime, std::vector> data); - TypedArray(TypedArray &&) = default; - TypedArray &operator=(TypedArray &&) = default; - - std::vector> toVector(jsi::Runtime &runtime); - void update(jsi::Runtime &runtime, const std::vector> &data); - void updateUnsafe(jsi::Runtime &runtime, ContentType *data, size_t length); - uint8_t* data(jsi::Runtime &runtime); +bool isTypedArray(jsi::Runtime& runtime, const jsi::Object& jsObj); +TypedArrayBase getTypedArray(jsi::Runtime& runtime, const jsi::Object& jsObj); + +std::vector arrayBufferToVector(jsi::Runtime& runtime, jsi::Object& jsObj); +void arrayBufferUpdate(jsi::Runtime& runtime, jsi::ArrayBuffer& buffer, std::vector data, + size_t offset); + +template class TypedArray : public TypedArrayBase { +public: + explicit TypedArray(TypedArrayBase&& base); + TypedArray(jsi::Runtime& runtime, size_t size); + TypedArray(jsi::Runtime& runtime, std::vector> data); + TypedArray(TypedArray&&) = default; + TypedArray& operator=(TypedArray&&) = default; + + std::vector> toVector(jsi::Runtime& runtime); + void update(jsi::Runtime& runtime, const std::vector>& data); + void updateUnsafe(jsi::Runtime& runtime, ContentType* data, size_t length); + uint8_t* data(jsi::Runtime& runtime); }; -template -TypedArray TypedArrayBase::get(jsi::Runtime &runtime) const & { +template TypedArray TypedArrayBase::get(jsi::Runtime& runtime) const& { assert(getKind(runtime) == T); (void)runtime; // when assert is disabled we need to mark this as used return TypedArray(jsi::Value(runtime, jsi::Value(runtime, *this).asObject(runtime))); } -template -TypedArray TypedArrayBase::get(jsi::Runtime &runtime) && { +template TypedArray TypedArrayBase::get(jsi::Runtime& runtime) && { assert(getKind(runtime) == T); (void)runtime; // when assert is disabled we need to mark this as used return TypedArray(std::move(*this)); } -template -TypedArray TypedArrayBase::as(jsi::Runtime &runtime) const & { +template TypedArray TypedArrayBase::as(jsi::Runtime& runtime) const& { if (getKind(runtime) != T) { throw jsi::JSError(runtime, "Object is not a TypedArray"); } return get(runtime); } -template -TypedArray TypedArrayBase::as(jsi::Runtime &runtime) && { +template TypedArray TypedArrayBase::as(jsi::Runtime& runtime) && { if (getKind(runtime) != T) { throw jsi::JSError(runtime, "Object is not a TypedArray"); } diff --git a/ios/JSIUtils.h b/ios/JSIUtils.h index 55e1c675..27c382b4 100644 --- a/ios/JSIUtils.h +++ b/ios/JSIUtils.h @@ -1,50 +1,38 @@ #import -#import #import +#import using namespace facebook; -jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value); -jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value); -jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value); -jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);; -jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value); -jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value); -std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value); -jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); -id convertJSIValueToObjCObject( - jsi::Runtime &runtime, - const jsi::Value &value); -NSString* convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value); -NSArray* convertJSIArrayToNSArray( - jsi::Runtime &runtime, - const jsi::Array &value); -NSDictionary *convertJSIObjectToNSDictionary( - jsi::Runtime &runtime, - const jsi::Object &value); -RCTResponseSenderBlock convertJSIFunctionToCallback( - jsi::Runtime &runtime, - const jsi::Function &value); -id convertJSIValueToObjCObject( - jsi::Runtime &runtime, - const jsi::Value &value); -RCTResponseSenderBlock convertJSIFunctionToCallback( - jsi::Runtime &runtime, - const jsi::Function &value); +jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime& runtime, NSNumber* value); +jsi::Value convertNSNumberToJSINumber(jsi::Runtime& runtime, NSNumber* value); +jsi::String convertNSStringToJSIString(jsi::Runtime& runtime, NSString* value); +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime& runtime, id value); +; +jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime& runtime, NSDictionary* value); +jsi::Array convertNSArrayToJSIArray(jsi::Runtime& runtime, NSArray* value); +std::vector convertNSArrayToStdVector(jsi::Runtime& runtime, NSArray* value); +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime& runtime, id value); +id convertJSIValueToObjCObject(jsi::Runtime& runtime, const jsi::Value& value); +NSString* convertJSIStringToNSString(jsi::Runtime& runtime, const jsi::String& value); +NSArray* convertJSIArrayToNSArray(jsi::Runtime& runtime, const jsi::Array& value); +NSDictionary* convertJSIObjectToNSDictionary(jsi::Runtime& runtime, const jsi::Object& value); +RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime& runtime, + const jsi::Function& value); +id convertJSIValueToObjCObject(jsi::Runtime& runtime, const jsi::Value& value); +RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime& runtime, + const jsi::Function& value); struct Promise { - Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject); + Promise(jsi::Runtime& rt, jsi::Function resolve, jsi::Function reject); - void resolve(const jsi::Value &result); - void reject(const std::string &error); + void resolve(const jsi::Value& result); + void reject(const std::string& error); - jsi::Runtime &runtime_; - jsi::Function resolve_; - jsi::Function reject_; + jsi::Runtime& runtime_; + jsi::Function resolve_; + jsi::Function reject_; }; -using PromiseSetupFunctionType = -std::function)>; -jsi::Value createPromiseAsJSIValue( - jsi::Runtime &rt, - const PromiseSetupFunctionType func); +using PromiseSetupFunctionType = std::function)>; +jsi::Value createPromiseAsJSIValue(jsi::Runtime& rt, const PromiseSetupFunctionType func); diff --git a/ios/JSIUtils.mm b/ios/JSIUtils.mm index 36a382f9..e3c14337 100644 --- a/ios/JSIUtils.mm +++ b/ios/JSIUtils.mm @@ -7,189 +7,161 @@ // #include "JSIUtils.h" -#import #import +#import /** * All helper functions are ObjC++ specific. */ -jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value) -{ - return jsi::Value((bool)[value boolValue]); +jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime& runtime, NSNumber* value) { + return jsi::Value((bool)[value boolValue]); } -jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value) -{ - return jsi::Value([value doubleValue]); +jsi::Value convertNSNumberToJSINumber(jsi::Runtime& runtime, NSNumber* value) { + return jsi::Value([value doubleValue]); } -jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value) -{ - return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: ""); +jsi::String convertNSStringToJSIString(jsi::Runtime& runtime, NSString* value) { + return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: ""); } -jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime& runtime, id value); -jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value) -{ - jsi::Object result = jsi::Object(runtime); - for (NSString *k in value) { - result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k])); - } - return result; +jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime& runtime, NSDictionary* value) { + jsi::Object result = jsi::Object(runtime); + for (NSString* k in value) { + result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k])); + } + return result; } -jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value) -{ - jsi::Array result = jsi::Array(runtime, value.count); - for (size_t i = 0; i < value.count; i++) { - result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i])); - } - return result; +jsi::Array convertNSArrayToJSIArray(jsi::Runtime& runtime, NSArray* value) { + jsi::Array result = jsi::Array(runtime, value.count); + for (size_t i = 0; i < value.count; i++) { + result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i])); + } + return result; } -std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value) -{ - std::vector result; - for (size_t i = 0; i < value.count; i++) { - result.emplace_back(convertObjCObjectToJSIValue(runtime, value[i])); - } - return result; +std::vector convertNSArrayToStdVector(jsi::Runtime& runtime, NSArray* value) { + std::vector result; + for (size_t i = 0; i < value.count; i++) { + result.emplace_back(convertObjCObjectToJSIValue(runtime, value[i])); + } + return result; } -jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) -{ - if ([value isKindOfClass:[NSString class]]) { - return convertNSStringToJSIString(runtime, (NSString *)value); - } else if ([value isKindOfClass:[NSNumber class]]) { - if ([value isKindOfClass:[@YES class]]) { - return convertNSNumberToJSIBoolean(runtime, (NSNumber *)value); - } - return convertNSNumberToJSINumber(runtime, (NSNumber *)value); - } else if ([value isKindOfClass:[NSDictionary class]]) { - return convertNSDictionaryToJSIObject(runtime, (NSDictionary *)value); - } else if ([value isKindOfClass:[NSArray class]]) { - return convertNSArrayToJSIArray(runtime, (NSArray *)value); - } else if (value == (id)kCFNull) { - return jsi::Value::null(); +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime& runtime, id value) { + if ([value isKindOfClass:[NSString class]]) { + return convertNSStringToJSIString(runtime, (NSString*)value); + } else if ([value isKindOfClass:[NSNumber class]]) { + if ([value isKindOfClass:[@YES class]]) { + return convertNSNumberToJSIBoolean(runtime, (NSNumber*)value); } - return jsi::Value::undefined(); + return convertNSNumberToJSINumber(runtime, (NSNumber*)value); + } else if ([value isKindOfClass:[NSDictionary class]]) { + return convertNSDictionaryToJSIObject(runtime, (NSDictionary*)value); + } else if ([value isKindOfClass:[NSArray class]]) { + return convertNSArrayToJSIArray(runtime, (NSArray*)value); + } else if (value == (id)kCFNull) { + return jsi::Value::null(); + } + return jsi::Value::undefined(); } -id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value); +id convertJSIValueToObjCObject(jsi::Runtime& runtime, const jsi::Value& value); -NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value) -{ - auto string = value.utf8(runtime); - return [NSString stringWithUTF8String:string.c_str()]; +NSString* convertJSIStringToNSString(jsi::Runtime& runtime, const jsi::String& value) { + auto string = value.utf8(runtime); + return [NSString stringWithUTF8String:string.c_str()]; } -NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, - const jsi::Array &value) -{ - size_t size = value.size(runtime); - NSMutableArray *result = [NSMutableArray new]; - for (size_t i = 0; i < size; i++) { - // Insert kCFNull when it's `undefined` value to preserve the indices. - [result - addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i)) ?: (id)kCFNull]; - } - return [result copy]; +NSArray* convertJSIArrayToNSArray(jsi::Runtime& runtime, const jsi::Array& value) { + size_t size = value.size(runtime); + NSMutableArray* result = [NSMutableArray new]; + for (size_t i = 0; i < size; i++) { + // Insert kCFNull when it's `undefined` value to preserve the indices. + [result addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i)) + ?: (id)kCFNull]; + } + return [result copy]; } -NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, - const jsi::Object &value) -{ - jsi::Array propertyNames = value.getPropertyNames(runtime); - size_t size = propertyNames.size(runtime); - NSMutableDictionary *result = [NSMutableDictionary new]; - for (size_t i = 0; i < size; i++) { - jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime); - NSString *k = convertJSIStringToNSString(runtime, name); - id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name)); - if (v) { - result[k] = v; - } +NSDictionary* convertJSIObjectToNSDictionary(jsi::Runtime& runtime, const jsi::Object& value) { + jsi::Array propertyNames = value.getPropertyNames(runtime); + size_t size = propertyNames.size(runtime); + NSMutableDictionary* result = [NSMutableDictionary new]; + for (size_t i = 0; i < size; i++) { + jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime); + NSString* k = convertJSIStringToNSString(runtime, name); + id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name)); + if (v) { + result[k] = v; } - return [result copy]; + } + return [result copy]; } -RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, - const jsi::Function &value) -{ - __block auto cb = value.getFunction(runtime); +RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime& runtime, + const jsi::Function& value) { + __block auto cb = value.getFunction(runtime); - return ^(NSArray *responses) { - cb.call(runtime, convertNSArrayToJSIArray(runtime, responses), 2); - }; + return ^(NSArray* responses) { + cb.call(runtime, convertNSArrayToJSIArray(runtime, responses), 2); + }; } -id convertJSIValueToObjCObject(jsi::Runtime &runtime, - const jsi::Value &value) -{ - if (value.isUndefined() || value.isNull()) { - return nil; - } - if (value.isBool()) { - return @(value.getBool()); - } - if (value.isNumber()) { - return @(value.getNumber()); - } - if (value.isString()) { - return convertJSIStringToNSString(runtime, value.getString(runtime)); +id convertJSIValueToObjCObject(jsi::Runtime& runtime, const jsi::Value& value) { + if (value.isUndefined() || value.isNull()) { + return nil; + } + if (value.isBool()) { + return @(value.getBool()); + } + if (value.isNumber()) { + return @(value.getNumber()); + } + if (value.isString()) { + return convertJSIStringToNSString(runtime, value.getString(runtime)); + } + if (value.isObject()) { + jsi::Object o = value.getObject(runtime); + if (o.isArray(runtime)) { + return convertJSIArrayToNSArray(runtime, o.getArray(runtime)); } - if (value.isObject()) { - jsi::Object o = value.getObject(runtime); - if (o.isArray(runtime)) { - return convertJSIArrayToNSArray(runtime, o.getArray(runtime)); - } - if (o.isFunction(runtime)) { - return convertJSIFunctionToCallback(runtime, - std::move(o.getFunction(runtime))); - } - return convertJSIObjectToNSDictionary(runtime, o); + if (o.isFunction(runtime)) { + return convertJSIFunctionToCallback(runtime, std::move(o.getFunction(runtime))); } + return convertJSIObjectToNSDictionary(runtime, o); + } - throw std::runtime_error("Unsupported jsi::jsi::Value kind"); + throw std::runtime_error("Unsupported jsi::jsi::Value kind"); } -Promise::Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject) -: runtime_(rt), resolve_(std::move(resolve)), reject_(std::move(reject)) {} +Promise::Promise(jsi::Runtime& rt, jsi::Function resolve, jsi::Function reject) + : runtime_(rt), resolve_(std::move(resolve)), reject_(std::move(reject)) {} -void Promise::resolve(const jsi::Value &result) -{ - resolve_.call(runtime_, result); +void Promise::resolve(const jsi::Value& result) { + resolve_.call(runtime_, result); } -void Promise::reject(const std::string &message) -{ - jsi::Object error(runtime_); - error.setProperty(runtime_, - "message", - jsi::String::createFromUtf8(runtime_, message)); - reject_.call(runtime_, error); +void Promise::reject(const std::string& message) { + jsi::Object error(runtime_); + error.setProperty(runtime_, "message", jsi::String::createFromUtf8(runtime_, message)); + reject_.call(runtime_, error); } -jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, - const PromiseSetupFunctionType func) -{ - jsi::Function JSPromise = rt.global().getPropertyAsFunction(rt, "Promise"); - jsi::Function fn = jsi::Function::createFromHostFunction(rt, - jsi::PropNameID::forAscii(rt, "fn"), - 2, - [func](jsi::Runtime &rt2, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { +jsi::Value createPromiseAsJSIValue(jsi::Runtime& rt, const PromiseSetupFunctionType func) { + jsi::Function JSPromise = rt.global().getPropertyAsFunction(rt, "Promise"); + jsi::Function fn = jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "fn"), 2, + [func](jsi::Runtime& rt2, const jsi::Value& thisVal, const jsi::Value* args, size_t count) { jsi::Function resolve = args[0].getObject(rt2).getFunction(rt2); jsi::Function reject = args[1].getObject(rt2).getFunction(rt2); - auto wrapper = std::make_shared(rt2, - std::move(resolve), - std::move(reject)); + auto wrapper = std::make_shared(rt2, std::move(resolve), std::move(reject)); func(rt2, wrapper); return jsi::Value::undefined(); - }); + }); - return JSPromise.callAsConstructor(rt, fn); + return JSPromise.callAsConstructor(rt, fn); } diff --git a/ios/MmkvHostObject.h b/ios/MmkvHostObject.h index d4c6f489..906156d9 100644 --- a/ios/MmkvHostObject.h +++ b/ios/MmkvHostObject.h @@ -9,12 +9,12 @@ #pragma once #import -#import #import +#import using namespace facebook; -class JSI_EXPORT MmkvHostObject: public jsi::HostObject { +class JSI_EXPORT MmkvHostObject : public jsi::HostObject { public: MmkvHostObject(NSString* instanceId, NSString* path, NSString* cryptKey); diff --git a/ios/MmkvHostObject.mm b/ios/MmkvHostObject.mm index 786d065b..16045fd7 100644 --- a/ios/MmkvHostObject.mm +++ b/ios/MmkvHostObject.mm @@ -6,25 +6,24 @@ // Copyright © 2021 Facebook. All rights reserved. // -#import #import "MmkvHostObject.h" -#import "JSIUtils.h" #import "../cpp/TypedArray.h" +#import "JSIUtils.h" +#import #import -MmkvHostObject::MmkvHostObject(NSString* instanceId, NSString* path, NSString* cryptKey) -{ +MmkvHostObject::MmkvHostObject(NSString* instanceId, NSString* path, NSString* cryptKey) { NSData* cryptData = cryptKey == nil ? nil : [cryptKey dataUsingEncoding:NSUTF8StringEncoding]; - + // Get appGroup value from info.plist using key "AppGroup" - NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + NSString* appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; if (appGroup == nil) { - instance = [MMKV mmkvWithID:instanceId cryptKey:cryptData rootPath:path]; + instance = [MMKV mmkvWithID:instanceId cryptKey:cryptData rootPath:path]; } else { - if (path != nil) { - NSLog(@"Warning: `path` is ignored when `appGroup` is set!"); - } - instance = [MMKV mmkvWithID:instanceId cryptKey:cryptData mode:MMKVMultiProcess]; + if (path != nil) { + NSLog(@"Warning: `path` is ignored when `appGroup` is set!"); + } + instance = [MMKV mmkvWithID:instanceId cryptKey:cryptData mode:MMKVMultiProcess]; } if (instance == nil) { @@ -35,7 +34,8 @@ // Check if encryptionKey is invalid if (cryptData != nil && [cryptData length] > 16) { - throw std::runtime_error("Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!"); + throw std::runtime_error( + "Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!"); } if (appGroup == nil) { @@ -43,7 +43,8 @@ NSFileManager* fileManager = [[NSFileManager alloc] init]; bool pathExists = [fileManager fileExistsAtPath:path isDirectory:nil]; if (!pathExists) { - throw std::runtime_error("Failed to create MMKV instance! The given Storage Path does not exist!"); + throw std::runtime_error( + "Failed to create MMKV instance! The given Storage Path does not exist!"); } } @@ -51,8 +52,7 @@ } } -std::vector MmkvHostObject::getPropertyNames(jsi::Runtime& rt) -{ +std::vector MmkvHostObject::getPropertyNames(jsi::Runtime& rt) { std::vector result; result.push_back(jsi::PropNameID::forUtf8(rt, std::string("set"))); result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBoolean"))); @@ -67,245 +67,228 @@ return result; } -jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) -{ +jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) { auto propName = propNameId.utf8(runtime); auto funcName = "MMKV." + propName; if (propName == "set") { // MMKV.set(key: string, value: string | number | bool) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 2, // key, value - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "MMKV::set: First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 2, // key, value + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, + "MMKV::set: First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - if (arguments[1].isBool()) { - // Set as boolean - [instance setBool:arguments[1].getBool() forKey:keyName]; - } else if (arguments[1].isNumber()) { - // Set as number (double in JS) - [instance setDouble:arguments[1].getNumber() forKey:keyName]; - } else if (arguments[1].isString()) { - // Set as UTF-8 string - auto stringValue = convertJSIStringToNSString(runtime, arguments[1].getString(runtime)); - [instance setString:stringValue forKey:keyName]; - } else if (arguments[1].isObject()) { - // object - auto object = arguments[1].asObject(runtime); - if (isTypedArray(runtime, object)) { - // Uint8Array - auto typedArray = getTypedArray(runtime, object); - auto bufferValue = typedArray.getBuffer(runtime); - auto data = [[NSData alloc] initWithBytes:bufferValue.data(runtime) - length:bufferValue.length(runtime)]; - [instance setData:data forKey:keyName]; - } else { - // unknown object - throw jsi::JSError(runtime, "MMKV::set: 'value' argument is an object, but not of type Uint8Array!"); - } - } else { - // Invalid type - throw jsi::JSError(runtime, "Second argument ('value') has to be of type bool, number or string!"); - } + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + if (arguments[1].isBool()) { + // Set as boolean + [instance setBool:arguments[1].getBool() forKey:keyName]; + } else if (arguments[1].isNumber()) { + // Set as number (double in JS) + [instance setDouble:arguments[1].getNumber() forKey:keyName]; + } else if (arguments[1].isString()) { + // Set as UTF-8 string + auto stringValue = convertJSIStringToNSString(runtime, arguments[1].getString(runtime)); + [instance setString:stringValue forKey:keyName]; + } else if (arguments[1].isObject()) { + // object + auto object = arguments[1].asObject(runtime); + if (isTypedArray(runtime, object)) { + // Uint8Array + auto typedArray = getTypedArray(runtime, object); + auto bufferValue = typedArray.getBuffer(runtime); + auto data = [[NSData alloc] initWithBytes:bufferValue.data(runtime) + length:bufferValue.length(runtime)]; + [instance setData:data forKey:keyName]; + } else { + // unknown object + throw jsi::JSError( + runtime, "MMKV::set: 'value' argument is an object, but not of type Uint8Array!"); + } + } else { + // Invalid type + throw jsi::JSError( + runtime, "Second argument ('value') has to be of type bool, number or string!"); + } - return jsi::Value::undefined(); - }); + return jsi::Value::undefined(); + }); } if (propName == "getBoolean") { // MMKV.getBoolean(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - BOOL hasValue; - auto value = [instance getBoolForKey:keyName defaultValue:false hasValue:&hasValue]; - if (hasValue) { - return jsi::Value(value == true); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + BOOL hasValue; + auto value = [instance getBoolForKey:keyName defaultValue:false hasValue:&hasValue]; + if (hasValue) { + return jsi::Value(value == true); + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "getString") { // MMKV.getString(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - auto value = [instance getStringForKey:keyName]; - if (value != nil) { - return convertNSStringToJSIString(runtime, value); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + auto value = [instance getStringForKey:keyName]; + if (value != nil) { + return convertNSStringToJSIString(runtime, value); + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "getNumber") { // MMKV.getNumber(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - BOOL hasValue; - auto value = [instance getDoubleForKey:keyName defaultValue:0.0 hasValue:&hasValue]; - if (hasValue) { - return jsi::Value(value); - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + BOOL hasValue; + auto value = [instance getDoubleForKey:keyName defaultValue:0.0 hasValue:&hasValue]; + if (hasValue) { + return jsi::Value(value); + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "getBuffer") { // MMKV.getBuffer(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - auto data = [instance getDataForKey:keyName]; - if (data != nil) { - TypedArray array(runtime, data.length); - auto charArray = static_cast([data bytes]); - std::vector vector(data.length); - vector.assign(charArray, charArray + data.length); - array.update(runtime, vector); - return array; - } else { - return jsi::Value::undefined(); - } - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + auto data = [instance getDataForKey:keyName]; + if (data != nil) { + TypedArray array(runtime, data.length); + auto charArray = static_cast([data bytes]); + std::vector vector(data.length); + vector.assign(charArray, charArray + data.length); + array.update(runtime, vector); + return array; + } else { + return jsi::Value::undefined(); + } + }); } if (propName == "contains") { // MMKV.contains(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - bool containsKey = [instance containsKey:keyName]; - return jsi::Value(containsKey); - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + bool containsKey = [instance containsKey:keyName]; + return jsi::Value(containsKey); + }); } if (propName == "delete") { // MMKV.delete(key: string) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // key - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (!arguments[0].isString()) { - throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); - } + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // key + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (!arguments[0].isString()) { + throw jsi::JSError(runtime, "First argument ('key') has to be of type string!"); + } - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - [instance removeValueForKey:keyName]; - return jsi::Value::undefined(); - }); + auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + [instance removeValueForKey:keyName]; + return jsi::Value::undefined(); + }); } if (propName == "getAllKeys") { // MMKV.getAllKeys() - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 0, - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - auto keys = [instance allKeys]; - return convertNSArrayToJSIArray(runtime, keys); - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), 0, + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + auto keys = [instance allKeys]; + return convertNSArrayToJSIArray(runtime, keys); + }); } if (propName == "clearAll") { // MMKV.clearAll() - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 0, - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - [instance clearAll]; - return jsi::Value::undefined(); - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), 0, + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + [instance clearAll]; + return jsi::Value::undefined(); + }); } if (propName == "recrypt") { // MMKV.recrypt(encryptionKey) - return jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, funcName), - 1, // encryptionKey - [this](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { - if (arguments[0].isUndefined()) { - // reset encryption key to "no encryption" - [instance reKey:nil]; - } else if (arguments[0].isString()) { - // reKey(..) with new encryption-key - NSString* encryptionKey = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - NSData* encryptionKeyBytes = [encryptionKey dataUsingEncoding:NSUTF8StringEncoding]; - [instance reKey:encryptionKeyBytes]; - } else { - throw jsi::JSError(runtime, "First argument ('encryptionKey') has to be of type string (or undefined)!"); - } - return jsi::Value::undefined(); - }); + return jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, funcName), + 1, // encryptionKey + [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (arguments[0].isUndefined()) { + // reset encryption key to "no encryption" + [instance reKey:nil]; + } else if (arguments[0].isString()) { + // reKey(..) with new encryption-key + NSString* encryptionKey = + convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); + NSData* encryptionKeyBytes = [encryptionKey dataUsingEncoding:NSUTF8StringEncoding]; + [instance reKey:encryptionKeyBytes]; + } else { + throw jsi::JSError( + runtime, + "First argument ('encryptionKey') has to be of type string (or undefined)!"); + } + return jsi::Value::undefined(); + }); } return jsi::Value::undefined(); diff --git a/ios/MmkvModule.mm b/ios/MmkvModule.mm index cf4fb83e..677145cd 100644 --- a/ios/MmkvModule.mm +++ b/ios/MmkvModule.mm @@ -5,9 +5,9 @@ #import #import -#import -#import "MmkvHostObject.h" #import "../cpp/TypedArray.h" +#import "MmkvHostObject.h" +#import using namespace facebook; @@ -17,69 +17,74 @@ @implementation MmkvModule + (NSString*)getPropertyAsStringOrNilFromObject:(jsi::Object&)object propertyName:(std::string)propertyName - runtime:(jsi::Runtime&)runtime -{ - jsi::Value value = object.getProperty(runtime, propertyName.c_str()); - std::string string = value.isString() ? value.asString(runtime).utf8(runtime) : ""; - return string.length() > 0 ? [NSString stringWithUTF8String:string.c_str()] : nil; + runtime:(jsi::Runtime&)runtime { + jsi::Value value = object.getProperty(runtime, propertyName.c_str()); + std::string string = value.isString() ? value.asString(runtime).utf8(runtime) : ""; + return string.length() > 0 ? [NSString stringWithUTF8String:string.c_str()] : nil; } -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install:(nullable NSString*)storageDirectory) -{ - NSLog(@"Installing global.mmkvCreateNewInstance..."); - RCTBridge* bridge = [RCTBridge currentBridge]; - RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge; - if (cxxBridge == nil) { - return @false; +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install : (nullable NSString*)storageDirectory) { + NSLog(@"Installing global.mmkvCreateNewInstance..."); + RCTBridge* bridge = [RCTBridge currentBridge]; + RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge; + if (cxxBridge == nil) { + return @false; + } + + using namespace facebook; + + auto jsiRuntime = (jsi::Runtime*)cxxBridge.runtime; + if (jsiRuntime == nil) { + return @false; + } + auto& runtime = *jsiRuntime; + + RCTUnsafeExecuteOnMainQueueSync(^{ + // Get appGroup value from info.plist using key "AppGroup" + NSString* appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + if (appGroup == nil) { + [MMKV initializeMMKV:storageDirectory]; + } else { + NSString* groupDir = [[NSFileManager defaultManager] + containerURLForSecurityApplicationGroupIdentifier:appGroup] + .path; + [MMKV initializeMMKV:nil groupDir:groupDir logLevel:MMKVLogNone]; } + }); - using namespace facebook; - - auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime; - if (jsiRuntime == nil) { - return @false; - } - auto& runtime = *jsiRuntime; - - RCTUnsafeExecuteOnMainQueueSync(^{ - // Get appGroup value from info.plist using key "AppGroup" - NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; - if (appGroup == nil) { - [MMKV initializeMMKV:storageDirectory]; - } else { - NSString *groupDir = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroup].path; - [MMKV initializeMMKV:nil groupDir:groupDir logLevel:MMKVLogNone]; - } - }); - - // MMKV.createNewInstance() - auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(runtime, - jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"), - 1, - [](jsi::Runtime& runtime, - const jsi::Value& thisValue, - const jsi::Value* arguments, - size_t count) -> jsi::Value { + // MMKV.createNewInstance() + auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"), 1, + [](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, + size_t count) -> jsi::Value { if (count != 1) { - throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!"); + throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!"); } jsi::Object config = arguments[0].asObject(runtime); - NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"id" runtime:runtime]; - NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"path" runtime:runtime]; - NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"encryptionKey" runtime:runtime]; + NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config + propertyName:"id" + runtime:runtime]; + NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config + propertyName:"path" + runtime:runtime]; + NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config + propertyName:"encryptionKey" + runtime:runtime]; auto instance = std::make_shared(instanceId, path, encryptionKey); return jsi::Object::createFromHostObject(runtime, instance); - }); - runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance)); + }); + runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance)); - // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets destroyed and the cache gets invalidated. - auto propNameIdCache = std::make_shared(runtime); - runtime.global().setProperty(runtime, "mmkvArrayBufferPropNameIdCache", jsi::Object::createFromHostObject(runtime, propNameIdCache)); + // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets + // destroyed and the cache gets invalidated. + auto propNameIdCache = std::make_shared(runtime); + runtime.global().setProperty(runtime, "mmkvArrayBufferPropNameIdCache", + jsi::Object::createFromHostObject(runtime, propNameIdCache)); - NSLog(@"Installed global.mmkvCreateNewInstance!"); - return @true; + NSLog(@"Installed global.mmkvCreateNewInstance!"); + return @true; } @end diff --git a/package.json b/package.json index 5a7f8dd6..df12533e 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "typescript": "tsc --noEmit", "lint": "eslint \"**/*.{js,ts,tsx}\"", "lint-ci": "yarn lint -f ./node_modules/@firmnav/eslint-github-actions-formatter/dist/formatter.js", + "lint-cpp": "scripts/clang-format.sh", "prepare": "git submodule update --init --recursive && bob build", "prepack": "bob build", "update-submodule": "git submodule update --remote --merge", diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh new file mode 100755 index 00000000..b2ef7dc7 --- /dev/null +++ b/scripts/clang-format.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if which clang-format >/dev/null; then + find cpp ios android/src/main/cpp -type f \( -name "*.h" -o -name "*.cpp" -o -name "*.m" -o -name "*.mm" \) -print0 | while read -d $'\0' file; do + echo "-> cpp-lint $file" + clang-format -i "$file" + done +else + echo "warning: clang-format not installed, download from https://clang.llvm.org/docs/ClangFormat.html (or run brew install clang-format)" +fi