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 nameVal = name.utf8(rt);
38   auto nameStr = nameVal.c_str();
39 
40   /** Check the static setters map */
41   const JsiPropertySettersMap &setters = getExportedPropertySettersMap();
42   auto setter = setters.find(nameStr);
43   if (setter != setters.end()) {
44     auto dispatcher = std::bind(setter->second, this, std::placeholders::_1,
45                                 std::placeholders::_2);
46     return dispatcher(rt, value);
47   }
48 
49   if (_propMap.count(nameStr) > 0) {
50     auto prop = _propMap.at(nameStr);
51     (prop.set)(rt, value);
52   }
53 }
54 
get(jsi::Runtime & runtime,const jsi::PropNameID & name)55 jsi::Value JsiHostObject::get(jsi::Runtime &runtime,
56                               const jsi::PropNameID &name) {
57   auto nameVal = name.utf8(runtime);
58   auto nameStr = nameVal.c_str();
59 
60   // Check the static getters map
61   const JsiPropertyGettersMap &getters = getExportedPropertyGettersMap();
62   auto getter = getters.find(nameStr);
63   if (getter != getters.end()) {
64     auto dispatcher = std::bind(getter->second, this, std::placeholders::_1);
65     return dispatcher(runtime);
66   }
67 
68   // Check the cache for functions
69   auto runtimeCache = _cache.find(&runtime);
70   JsiHostFunctionCache *currentCache;
71   if (runtimeCache != _cache.end()) {
72     currentCache = &runtimeCache->second;
73     // Check if the runtime cache as a cache of the host function
74     auto cachedFunc = runtimeCache->second.find(nameStr);
75     if (cachedFunc != runtimeCache->second.end()) {
76       return cachedFunc->second->asFunction(runtime);
77     }
78   } else {
79     // Create cache for this runtime
80     JsiHostFunctionCache runtimeCache;
81     _cache.emplace(&runtime, JsiHostFunctionCache{});
82     currentCache = &_cache.at(&runtime);
83   }
84 
85   // Check the static function map
86   const JsiFunctionMap &funcs = getExportedFunctionMap();
87   auto func = funcs.find(nameStr);
88   if (func != funcs.end()) {
89     auto dispatcher = std::bind(func->second, (JsiHostObject *)this,
90                                 std::placeholders::_1, std::placeholders::_2,
91                                 std::placeholders::_3, std::placeholders::_4);
92 
93     // Add to cache
94     currentCache->emplace(nameStr, std::make_unique<jsi::Function>(
95                                        jsi::Function::createFromHostFunction(
96                                            runtime, name, 0, dispatcher)));
97 
98     // return retVal;
99     return currentCache->at(nameStr)->asFunction(runtime);
100   }
101 
102   if (_funcMap.count(nameStr) > 0) {
103     return jsi::Function::createFromHostFunction(runtime, name, 0,
104                                                  _funcMap.at(nameStr));
105   }
106 
107   if (_propMap.count(nameStr) > 0) {
108     auto prop = _propMap.at(nameStr);
109     return (prop.get)(runtime);
110   }
111 
112   return jsi::Value::undefined();
113 }
114 
115 std::vector<jsi::PropNameID>
getPropertyNames(jsi::Runtime & runtime)116 JsiHostObject::getPropertyNames(jsi::Runtime &runtime) {
117   // statically exported functions
118   const auto& funcs = getExportedFunctionMap();
119 
120   // Statically exported property getters
121   const auto& getters = getExportedPropertyGettersMap();
122 
123   // Statically exported property setters
124   const auto& setters = getExportedPropertySettersMap();
125 
126   std::vector<jsi::PropNameID> propNames;
127   propNames.reserve(funcs.size() + getters.size() + setters.size() + _funcMap.size() + _propMap.size());
128 
129   for (auto it = funcs.cbegin(); it != funcs.cend(); ++it) {
130     propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
131   }
132 
133   for (auto it = getters.cbegin(); it != getters.cend(); ++it) {
134     propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first));
135   }
136 
137   for (auto it = getters.cbegin(); it != getters.cend(); ++it) {
138     if (getters.count(it->first) == 0) {
139       propNames.push_back(jsi::PropNameID::forUtf8(runtime, it->first));
140     }
141   }
142 
143   // functions
144   for (auto it = _funcMap.cbegin(); it != _funcMap.cend(); ++it) {
145     propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
146   }
147   // props
148   for (auto it = _propMap.cbegin(); it != _propMap.cend(); ++it) {
149     propNames.push_back(jsi::PropNameID::forAscii(runtime, it->first));
150   }
151   return propNames;
152 }
153 
154 } // namespace RNJsi
155