1 #include <JsiHostObject.h>
2 #include <functional>
3 #include <vector>
4
5 // To be able to find objects that aren't cleaned up correctly,
6 // we can set this value to 1 and debug the constructor/destructor
7 #define JSI_DEBUG_ALLOCATIONS 0
8
9 namespace RNJsi {
10
11 #if JSI_DEBUG_ALLOCATIONS
12 int objCounter = 0;
13 std::vector<JsiHostObject *> objects;
14 #endif
15
JsiHostObject()16 JsiHostObject::JsiHostObject() {
17 #if JSI_DEBUG_ALLOCATIONS
18 objects.push_back(this);
19 objCounter++;
20 #endif
21 }
~JsiHostObject()22 JsiHostObject::~JsiHostObject() {
23 #if JSI_DEBUG_ALLOCATIONS
24 for (size_t i = 0; i < objects.size(); ++i) {
25 if (objects.at(i) == this) {
26 objects.erase(objects.begin() + i);
27 break;
28 }
29 }
30 objCounter--;
31 #endif
32 }
33
set(jsi::Runtime & rt,const jsi::PropNameID & name,const jsi::Value & value)34 void JsiHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name,
35 const jsi::Value &value) {
36
37 auto nameStr = name.utf8(rt);
38
39 /** Check the static setters map */
40 const JsiPropertySettersMap &setters = getExportedPropertySettersMap();
41 auto setter = setters.find(nameStr);
42 if (setter != setters.end()) {
43 auto dispatcher = std::bind(setter->second, this, std::placeholders::_1,
44 std::placeholders::_2);
45 return dispatcher(rt, value);
46 }
47
48 if (_propMap.count(nameStr) > 0) {
49 auto prop = _propMap.at(nameStr);
50 (prop.set)(rt, value);
51 }
52 }
53
get(jsi::Runtime & runtime,const jsi::PropNameID & name)54 jsi::Value JsiHostObject::get(jsi::Runtime &runtime,
55 const jsi::PropNameID &name) {
56 auto nameStr = name.utf8(runtime);
57
58 // Do the happy-paths first
59
60 // Check function cache
61 auto cachedFunc = _hostFunctionCache.find(nameStr);
62 if (cachedFunc != _hostFunctionCache.end()) {
63 return cachedFunc->second.asFunction(runtime);
64 }
65
66 // Check the static getters map
67 const JsiPropertyGettersMap &getters = getExportedPropertyGettersMap();
68 auto getter = getters.find(nameStr);
69 if (getter != getters.end()) {
70 auto dispatcher = std::bind(getter->second, this, std::placeholders::_1);
71 return dispatcher(runtime);
72 }
73
74 // Check the static function map
75 const JsiFunctionMap &funcs = getExportedFunctionMap();
76 auto func = funcs.find(nameStr);
77 if (func != funcs.end()) {
78 auto dispatcher =
79 std::bind(func->second, reinterpret_cast<JsiHostObject *>(this),
80 std::placeholders::_1, std::placeholders::_2,
81 std::placeholders::_3, std::placeholders::_4);
82
83 // Add to cache - it is important to cache the results from the
84 // createFromHostFunction function which takes some time.
85 return _hostFunctionCache
86 .emplace(nameStr, jsi::Function::createFromHostFunction(runtime, name,
87 0, dispatcher))
88 .first->second.asFunction(runtime);
89 }
90
91 if (_funcMap.count(nameStr) > 0) {
92 return jsi::Function::createFromHostFunction(runtime, name, 0,
93 _funcMap.at(nameStr));
94 }
95
96 if (_propMap.count(nameStr) > 0) {
97 auto prop = _propMap.at(nameStr);
98 return (prop.get)(runtime);
99 }
100
101 return jsi::Value::undefined();
102 }
103
104 std::vector<jsi::PropNameID>
getPropertyNames(jsi::Runtime & runtime)105 JsiHostObject::getPropertyNames(jsi::Runtime &runtime) {
106 // statically exported functions
107 const auto &funcs = getExportedFunctionMap();
108
109 // Statically exported property getters
110 const auto &getters = getExportedPropertyGettersMap();
111
112 // Statically exported property setters
113 const auto &setters = getExportedPropertySettersMap();
114
115 std::vector<jsi::PropNameID> propNames;
116 propNames.reserve(funcs.size() + getters.size() + setters.size() +
117 _funcMap.size() + _propMap.size());
118
119 for (auto it = funcs.cbegin(); it != funcs.cend(); ++it) {
120 propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
121 }
122
123 for (auto it = getters.cbegin(); it != getters.cend(); ++it) {
124 propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first));
125 }
126
127 for (auto it = getters.cbegin(); it != getters.cend(); ++it) {
128 if (getters.count(it->first) == 0) {
129 propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first));
130 }
131 }
132
133 // functions
134 for (auto it = _funcMap.cbegin(); it != _funcMap.cend(); ++it) {
135 propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
136 }
137 // props
138 for (auto it = _propMap.cbegin(); it != _propMap.cend(); ++it) {
139 propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
140 }
141 return propNames;
142 }
143
144 } // namespace RNJsi
145