react-native-mmkv 4.0.0-beta.4 → 4.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cpp/HybridMMKV.cpp +184 -0
- package/cpp/HybridMMKV.hpp +47 -0
- package/cpp/HybridMMKVFactory.cpp +33 -0
- package/cpp/HybridMMKVFactory.hpp +24 -0
- package/cpp/MMKVTypes.hpp +50 -0
- package/cpp/MMKVValueChangedListenerRegistry.cpp +58 -0
- package/cpp/MMKVValueChangedListenerRegistry.hpp +43 -0
- package/cpp/ManagedMMBuffer.hpp +40 -0
- package/nitro.json +2 -1
- package/nitrogen/generated/.gitattributes +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HybridMMKV.cpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "HybridMMKV.hpp"
|
|
9
|
+
#include "MMKVTypes.hpp"
|
|
10
|
+
#include "MMKVValueChangedListenerRegistry.hpp"
|
|
11
|
+
#include "ManagedMMBuffer.hpp"
|
|
12
|
+
#include <NitroModules/NitroLogger.hpp>
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro::mmkv {
|
|
15
|
+
|
|
16
|
+
HybridMMKV::HybridMMKV(const Configuration& config) : HybridObject(TAG) {
|
|
17
|
+
std::string path = config.path.has_value() ? config.path.value() : "";
|
|
18
|
+
std::string encryptionKey = config.encryptionKey.has_value() ? config.encryptionKey.value() : "";
|
|
19
|
+
bool hasEncryptionKey = encryptionKey.size() > 0;
|
|
20
|
+
Logger::log(LogLevel::Info, TAG, "Creating MMKV instance \"%s\"... (Path: %s, Encrypted: %s)", config.id.c_str(), path.c_str(),
|
|
21
|
+
hasEncryptionKey ? "true" : "false");
|
|
22
|
+
|
|
23
|
+
std::string* pathPtr = path.size() > 0 ? &path : nullptr;
|
|
24
|
+
std::string* encryptionKeyPtr = encryptionKey.size() > 0 ? &encryptionKey : nullptr;
|
|
25
|
+
MMKVMode mode = getMMKVMode(config);
|
|
26
|
+
if (config.readOnly.has_value() && config.readOnly.value()) {
|
|
27
|
+
Logger::log(LogLevel::Info, TAG, "Instance is read-only!");
|
|
28
|
+
mode = mode | ::mmkv::MMKV_READ_ONLY;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#ifdef __APPLE__
|
|
32
|
+
instance = MMKV::mmkvWithID(config.id, mode, encryptionKeyPtr, pathPtr);
|
|
33
|
+
#else
|
|
34
|
+
instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr);
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
if (instance == nullptr) [[unlikely]] {
|
|
38
|
+
// Check if instanceId is invalid
|
|
39
|
+
if (config.id.empty()) [[unlikely]] {
|
|
40
|
+
throw std::runtime_error("Failed to create MMKV instance! `id` cannot be empty!");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if encryptionKey is invalid
|
|
44
|
+
if (encryptionKey.size() > 16) [[unlikely]] {
|
|
45
|
+
throw std::runtime_error("Failed to create MMKV instance! `encryptionKey` cannot be longer "
|
|
46
|
+
"than 16 bytes!");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check if path is maybe invalid
|
|
50
|
+
if (path.empty()) [[unlikely]] {
|
|
51
|
+
throw std::runtime_error("Failed to create MMKV instance! `path` cannot be empty!");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw std::runtime_error("Failed to create MMKV instance!");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
double HybridMMKV::getSize() {
|
|
59
|
+
return instance->actualSize();
|
|
60
|
+
}
|
|
61
|
+
bool HybridMMKV::getIsReadOnly() {
|
|
62
|
+
return instance->isReadOnly();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// helper: overload pattern matching for lambdas
|
|
66
|
+
template <class... Ts>
|
|
67
|
+
struct overloaded : Ts... {
|
|
68
|
+
using Ts::operator()...;
|
|
69
|
+
};
|
|
70
|
+
template <class... Ts>
|
|
71
|
+
overloaded(Ts...) -> overloaded<Ts...>;
|
|
72
|
+
|
|
73
|
+
void HybridMMKV::set(const std::string& key, const std::variant<std::string, double, bool, std::shared_ptr<ArrayBuffer>>& value) {
|
|
74
|
+
// Pattern-match each potential value in std::variant
|
|
75
|
+
std::visit(overloaded{[&](const std::string& string) { instance->set(string, key); }, [&](double number) { instance->set(number, key); },
|
|
76
|
+
[&](bool b) { instance->set(b, key); },
|
|
77
|
+
[&](const std::shared_ptr<ArrayBuffer>& buf) {
|
|
78
|
+
MMBuffer buffer(buf->data(), buf->size(), MMBufferCopyFlag::MMBufferNoCopy);
|
|
79
|
+
instance->set(std::move(buffer), key);
|
|
80
|
+
}},
|
|
81
|
+
value);
|
|
82
|
+
|
|
83
|
+
// Notify on changed
|
|
84
|
+
MMKVValueChangedListenerRegistry::notifyOnValueChanged(instance->mmapID(), key);
|
|
85
|
+
}
|
|
86
|
+
std::optional<bool> HybridMMKV::getBoolean(const std::string& key) {
|
|
87
|
+
bool hasValue;
|
|
88
|
+
bool result = instance->getBool(key, /* defaultValue */ false, &hasValue);
|
|
89
|
+
if (hasValue) {
|
|
90
|
+
return result;
|
|
91
|
+
} else {
|
|
92
|
+
return std::nullopt;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
std::optional<std::string> HybridMMKV::getString(const std::string& key) {
|
|
96
|
+
std::string result;
|
|
97
|
+
bool hasValue = instance->getString(key, result, /* inplaceModification */ true);
|
|
98
|
+
if (hasValue) {
|
|
99
|
+
return result;
|
|
100
|
+
} else {
|
|
101
|
+
return std::nullopt;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
std::optional<double> HybridMMKV::getNumber(const std::string& key) {
|
|
105
|
+
bool hasValue;
|
|
106
|
+
double result = instance->getDouble(key, /* defaultValue */ 0.0, &hasValue);
|
|
107
|
+
if (hasValue) {
|
|
108
|
+
return result;
|
|
109
|
+
} else {
|
|
110
|
+
return std::nullopt;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
std::optional<std::shared_ptr<ArrayBuffer>> HybridMMKV::getBuffer(const std::string& key) {
|
|
114
|
+
MMBuffer result;
|
|
115
|
+
#ifdef __APPLE__
|
|
116
|
+
// iOS: Convert std::string to NSString* for MMKVCore pod compatibility
|
|
117
|
+
bool hasValue = instance->getBytes(@(key.c_str()), result);
|
|
118
|
+
#else
|
|
119
|
+
// Android/other platforms: Use std::string directly (converts to
|
|
120
|
+
// std::string_view)
|
|
121
|
+
bool hasValue = instance->getBytes(key, result);
|
|
122
|
+
#endif
|
|
123
|
+
if (hasValue) {
|
|
124
|
+
return std::make_shared<ManagedMMBuffer>(std::move(result));
|
|
125
|
+
} else {
|
|
126
|
+
return std::nullopt;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
bool HybridMMKV::contains(const std::string& key) {
|
|
130
|
+
return instance->containsKey(key);
|
|
131
|
+
}
|
|
132
|
+
void HybridMMKV::remove(const std::string& key) {
|
|
133
|
+
instance->removeValueForKey(key);
|
|
134
|
+
}
|
|
135
|
+
std::vector<std::string> HybridMMKV::getAllKeys() {
|
|
136
|
+
return instance->allKeys();
|
|
137
|
+
}
|
|
138
|
+
void HybridMMKV::clearAll() {
|
|
139
|
+
instance->clearAll();
|
|
140
|
+
}
|
|
141
|
+
void HybridMMKV::recrypt(const std::optional<std::string>& key) {
|
|
142
|
+
bool successful = false;
|
|
143
|
+
if (key.has_value()) {
|
|
144
|
+
// Encrypt with the given key
|
|
145
|
+
successful = instance->reKey(key.value());
|
|
146
|
+
} else {
|
|
147
|
+
// Remove the encryption key by setting it to a blank string
|
|
148
|
+
successful = instance->reKey(std::string());
|
|
149
|
+
}
|
|
150
|
+
if (!successful) {
|
|
151
|
+
throw std::runtime_error("Failed to recrypt MMKV instance!");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
void HybridMMKV::trim() {
|
|
155
|
+
instance->trim();
|
|
156
|
+
instance->clearMemoryCache();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Listener HybridMMKV::addOnValueChangedListener(const std::function<void(const std::string& /* key */)>& onValueChanged) {
|
|
160
|
+
// Add listener
|
|
161
|
+
auto mmkvID = instance->mmapID();
|
|
162
|
+
auto listenerID = MMKVValueChangedListenerRegistry::addListener(instance->mmapID(), onValueChanged);
|
|
163
|
+
|
|
164
|
+
return Listener([=]() {
|
|
165
|
+
// remove()
|
|
166
|
+
MMKVValueChangedListenerRegistry::removeListener(mmkvID, listenerID);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
MMKVMode HybridMMKV::getMMKVMode(const Configuration& config) {
|
|
171
|
+
if (!config.mode.has_value()) {
|
|
172
|
+
return ::mmkv::MMKV_SINGLE_PROCESS;
|
|
173
|
+
}
|
|
174
|
+
switch (config.mode.value()) {
|
|
175
|
+
case Mode::SINGLE_PROCESS:
|
|
176
|
+
return ::mmkv::MMKV_SINGLE_PROCESS;
|
|
177
|
+
case Mode::MULTI_PROCESS:
|
|
178
|
+
return ::mmkv::MMKV_MULTI_PROCESS;
|
|
179
|
+
default:
|
|
180
|
+
[[unlikely]] throw std::runtime_error("Invalid MMKV Mode value!");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HybridMMKV.hpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "Configuration.hpp"
|
|
11
|
+
#include "HybridMMKVSpec.hpp"
|
|
12
|
+
#include "MMKVTypes.hpp"
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro::mmkv {
|
|
15
|
+
|
|
16
|
+
class HybridMMKV final : public HybridMMKVSpec {
|
|
17
|
+
public:
|
|
18
|
+
explicit HybridMMKV(const Configuration& configuration);
|
|
19
|
+
|
|
20
|
+
public:
|
|
21
|
+
// Properties
|
|
22
|
+
double getSize() override;
|
|
23
|
+
bool getIsReadOnly() override;
|
|
24
|
+
|
|
25
|
+
public:
|
|
26
|
+
// Methods
|
|
27
|
+
void set(const std::string& key, const std::variant<std::string, double, bool, std::shared_ptr<ArrayBuffer>>& value) override;
|
|
28
|
+
std::optional<bool> getBoolean(const std::string& key) override;
|
|
29
|
+
std::optional<std::string> getString(const std::string& key) override;
|
|
30
|
+
std::optional<double> getNumber(const std::string& key) override;
|
|
31
|
+
std::optional<std::shared_ptr<ArrayBuffer>> getBuffer(const std::string& key) override;
|
|
32
|
+
bool contains(const std::string& key) override;
|
|
33
|
+
void remove(const std::string& key) override;
|
|
34
|
+
std::vector<std::string> getAllKeys() override;
|
|
35
|
+
void clearAll() override;
|
|
36
|
+
void recrypt(const std::optional<std::string>& key) override;
|
|
37
|
+
void trim() override;
|
|
38
|
+
Listener addOnValueChangedListener(const std::function<void(const std::string& /* key */)>& onValueChanged) override;
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
static MMKVMode getMMKVMode(const Configuration& config);
|
|
42
|
+
|
|
43
|
+
private:
|
|
44
|
+
MMKV* instance;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HybridMMKVFactory.cpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "HybridMMKVFactory.hpp"
|
|
9
|
+
#include "HybridMMKV.hpp"
|
|
10
|
+
#include "MMKVTypes.hpp"
|
|
11
|
+
|
|
12
|
+
namespace margelo::nitro::mmkv {
|
|
13
|
+
|
|
14
|
+
std::string HybridMMKVFactory::getDefaultMMKVInstanceId() {
|
|
15
|
+
return DEFAULT_MMAP_ID;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
std::shared_ptr<HybridMMKVSpec> HybridMMKVFactory::createMMKV(const Configuration& configuration) {
|
|
19
|
+
return std::make_shared<HybridMMKV>(configuration);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void HybridMMKVFactory::initializeMMKV(const std::string& rootPath) {
|
|
23
|
+
Logger::log(LogLevel::Info, TAG, "Initializing MMKV with rootPath=%s", rootPath.c_str());
|
|
24
|
+
|
|
25
|
+
#ifdef NITRO_DEBUG
|
|
26
|
+
MMKVLogLevel logLevel = ::mmkv::MMKVLogDebug;
|
|
27
|
+
#else
|
|
28
|
+
MMKVLogLevel logLevel = ::mmkv::MMKVLogWarning;
|
|
29
|
+
#endif
|
|
30
|
+
MMKV::initializeMMKV(rootPath, logLevel);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HybridMMKVFactory.hpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "HybridMMKVFactorySpec.hpp"
|
|
11
|
+
|
|
12
|
+
namespace margelo::nitro::mmkv {
|
|
13
|
+
|
|
14
|
+
class HybridMMKVFactory final : public HybridMMKVFactorySpec {
|
|
15
|
+
public:
|
|
16
|
+
HybridMMKVFactory() : HybridObject(TAG) {}
|
|
17
|
+
|
|
18
|
+
public:
|
|
19
|
+
std::string getDefaultMMKVInstanceId() override;
|
|
20
|
+
std::shared_ptr<HybridMMKVSpec> createMMKV(const Configuration& configuration) override;
|
|
21
|
+
void initializeMMKV(const std::string& rootPath) override;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MMKVTypes.h
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Brad Anderson on 10.08.2025.
|
|
6
|
+
// Platform-specific MMKV type unification header
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
|
|
11
|
+
// Platform-specific MMKV includes
|
|
12
|
+
#ifdef __ANDROID__
|
|
13
|
+
#include <MMKV/MMKV.h>
|
|
14
|
+
|
|
15
|
+
// On Android, bring global namespace types into mmkv namespace for consistency
|
|
16
|
+
namespace mmkv {
|
|
17
|
+
using MMKV = ::MMKV;
|
|
18
|
+
using MMKVMode = ::MMKVMode;
|
|
19
|
+
using MMKVLogLevel = ::MMKVLogLevel;
|
|
20
|
+
|
|
21
|
+
// Constants - bring into mmkv namespace
|
|
22
|
+
constexpr auto MMKVLogDebug = ::MMKVLogDebug;
|
|
23
|
+
constexpr auto MMKVLogInfo = ::MMKVLogInfo;
|
|
24
|
+
constexpr auto MMKVLogWarning = ::MMKVLogWarning;
|
|
25
|
+
constexpr auto MMKVLogError = ::MMKVLogError;
|
|
26
|
+
constexpr auto MMKVLogNone = ::MMKVLogNone;
|
|
27
|
+
|
|
28
|
+
constexpr auto MMKV_SINGLE_PROCESS = ::MMKV_SINGLE_PROCESS;
|
|
29
|
+
constexpr auto MMKV_MULTI_PROCESS = ::MMKV_MULTI_PROCESS;
|
|
30
|
+
constexpr auto MMKV_READ_ONLY = ::MMKVMode::MMKV_READ_ONLY;
|
|
31
|
+
} // namespace mmkv
|
|
32
|
+
|
|
33
|
+
#else
|
|
34
|
+
#include <MMKVCore/MMKV.h>
|
|
35
|
+
// iOS already has everything in mmkv:: namespace
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Unified MMKV namespace usage for cross-platform compatibility.
|
|
40
|
+
*
|
|
41
|
+
* After including this header, use:
|
|
42
|
+
* - mmkv::MMKV for the main class
|
|
43
|
+
* - mmkv::MMKVMode for mode enum
|
|
44
|
+
* - mmkv::MMKVLogLevel for log level enum
|
|
45
|
+
* - mmkv::MMBuffer for buffer type
|
|
46
|
+
* - mmkv::MMKV_SINGLE_PROCESS / mmkv::MMKV_MULTI_PROCESS for modes
|
|
47
|
+
* - mmkv::MMKVLogDebug, etc. for log levels
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
using namespace mmkv;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MMKVValueChangedListenerRegistry.cpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "MMKVValueChangedListenerRegistry.hpp"
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro::mmkv {
|
|
11
|
+
|
|
12
|
+
// static members
|
|
13
|
+
std::atomic<ListenerID> MMKVValueChangedListenerRegistry::_listenersCounter = 0;
|
|
14
|
+
std::unordered_map<MMKVID, std::vector<ListenerSubscription>> MMKVValueChangedListenerRegistry::_listeners;
|
|
15
|
+
|
|
16
|
+
ListenerID MMKVValueChangedListenerRegistry::addListener(const std::string& mmkvID,
|
|
17
|
+
const std::function<void(const std::string& /* key */)>& callback) {
|
|
18
|
+
// 1. Get (or create) the listeners array for these MMKV instances
|
|
19
|
+
auto& listeners = _listeners[mmkvID];
|
|
20
|
+
// 2. Get (and increment) the listener ID counter
|
|
21
|
+
auto id = _listenersCounter.fetch_add(1);
|
|
22
|
+
// 3. Add the listener to our array
|
|
23
|
+
listeners.push_back(ListenerSubscription{
|
|
24
|
+
.id = id,
|
|
25
|
+
.callback = callback,
|
|
26
|
+
});
|
|
27
|
+
// 4. Return the ID used to unsubscribe later on
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void MMKVValueChangedListenerRegistry::removeListener(const std::string& mmkvID, ListenerID id) {
|
|
32
|
+
// 1. Get the listeners array for these MMKV instances
|
|
33
|
+
auto entry = _listeners.find(mmkvID);
|
|
34
|
+
if (entry == _listeners.end()) {
|
|
35
|
+
// There's no more listeners for this instance anyways.
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// 2. Remove all listeners where the ID matches. Should only be one.
|
|
39
|
+
auto& listeners = entry->second;
|
|
40
|
+
listeners.erase(std::remove_if(listeners.begin(), listeners.end(), [id](const ListenerSubscription& e) { return e.id == id; }),
|
|
41
|
+
listeners.end());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void MMKVValueChangedListenerRegistry::notifyOnValueChanged(const std::string& mmkvID, const std::string& key) {
|
|
45
|
+
// 1. Get all listeners for the specific MMKV ID
|
|
46
|
+
auto entry = _listeners.find(mmkvID);
|
|
47
|
+
if (entry == _listeners.end()) {
|
|
48
|
+
// There are no listeners. Return
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// 2. Call each listener.
|
|
52
|
+
auto& listeners = entry->second;
|
|
53
|
+
for (const auto& listener : listeners) {
|
|
54
|
+
listener.callback(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MMKVValueChangedListenerRegistry.hpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 21.08.2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "MMKVTypes.hpp"
|
|
9
|
+
#include <atomic>
|
|
10
|
+
#include <unordered_map>
|
|
11
|
+
|
|
12
|
+
namespace margelo::nitro::mmkv {
|
|
13
|
+
|
|
14
|
+
using ListenerID = size_t;
|
|
15
|
+
using MMKVID = std::string;
|
|
16
|
+
|
|
17
|
+
struct ListenerSubscription {
|
|
18
|
+
ListenerID id;
|
|
19
|
+
std::function<void(const std::string& /* key */)> callback;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Listeners are tracked across instances - so we need an extra static class for
|
|
24
|
+
* the registry.
|
|
25
|
+
*/
|
|
26
|
+
class MMKVValueChangedListenerRegistry final {
|
|
27
|
+
public:
|
|
28
|
+
MMKVValueChangedListenerRegistry() = delete;
|
|
29
|
+
~MMKVValueChangedListenerRegistry() = delete;
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
static ListenerID addListener(const std::string& mmkvID, const std::function<void(const std::string& /* key */)>& callback);
|
|
33
|
+
static void removeListener(const std::string& mmkvID, ListenerID id);
|
|
34
|
+
|
|
35
|
+
public:
|
|
36
|
+
static void notifyOnValueChanged(const std::string& mmkvID, const std::string& key);
|
|
37
|
+
|
|
38
|
+
private:
|
|
39
|
+
static std::atomic<ListenerID> _listenersCounter;
|
|
40
|
+
static std::unordered_map<MMKVID, std::vector<ListenerSubscription>> _listeners;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
} // namespace margelo::nitro::mmkv
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ManagedMMBuffer.h
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "MMKVTypes.hpp"
|
|
11
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
12
|
+
|
|
13
|
+
namespace margelo::nitro::mmkv {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
An ArrayBuffer subclass that manages MMBuffer memory (by ownership).
|
|
17
|
+
*/
|
|
18
|
+
class ManagedMMBuffer : public ArrayBuffer {
|
|
19
|
+
public:
|
|
20
|
+
explicit ManagedMMBuffer(MMBuffer&& buffer) : _buffer(std::move(buffer)) {}
|
|
21
|
+
|
|
22
|
+
public:
|
|
23
|
+
bool isOwner() const noexcept override {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public:
|
|
28
|
+
uint8_t* data() override {
|
|
29
|
+
return static_cast<uint8_t*>(_buffer.getPtr());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
size_t size() const override {
|
|
33
|
+
return _buffer.length();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private:
|
|
37
|
+
MMBuffer _buffer;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
} // namespace margelo::nitro::mmkv
|
package/nitro.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
** linguist-generated=
|
|
1
|
+
** linguist-generated=false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mmkv",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.6",
|
|
4
4
|
"description": "react-native-mmkv",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"module": "lib/index",
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
"ios/**/*.mm",
|
|
23
23
|
"ios/**/*.cpp",
|
|
24
24
|
"ios/**/*.swift",
|
|
25
|
+
"cpp/**/*.h",
|
|
26
|
+
"cpp/**/*.hpp",
|
|
27
|
+
"cpp/**/*.cpp",
|
|
25
28
|
"app.plugin.js",
|
|
26
29
|
"nitro.json",
|
|
27
30
|
"*.podspec",
|