1*753557f6STomasz Sapeta #include "MutableValue.h"
2*753557f6STomasz Sapeta #include "RuntimeDecorator.h"
3*753557f6STomasz Sapeta #include "RuntimeManager.h"
4*753557f6STomasz Sapeta #include "ShareableValue.h"
5*753557f6STomasz Sapeta #include "SharedParent.h"
6*753557f6STomasz Sapeta 
7*753557f6STomasz Sapeta #include <string>
8*753557f6STomasz Sapeta 
9*753557f6STomasz Sapeta namespace ABI47_0_0reanimated {
10*753557f6STomasz Sapeta 
setValue(jsi::Runtime & rt,const jsi::Value & newValue)11*753557f6STomasz Sapeta void MutableValue::setValue(jsi::Runtime &rt, const jsi::Value &newValue) {
12*753557f6STomasz Sapeta   std::lock_guard<std::mutex> lock(readWriteMutex);
13*753557f6STomasz Sapeta   value = ShareableValue::adapt(rt, newValue, runtimeManager);
14*753557f6STomasz Sapeta 
15*753557f6STomasz Sapeta   std::shared_ptr<MutableValue> thiz = shared_from_this();
16*753557f6STomasz Sapeta   auto notifyListeners = [thiz]() {
17*753557f6STomasz Sapeta     for (auto listener : thiz->listeners) {
18*753557f6STomasz Sapeta       listener.second();
19*753557f6STomasz Sapeta     }
20*753557f6STomasz Sapeta   };
21*753557f6STomasz Sapeta   if (RuntimeDecorator::isUIRuntime(rt)) {
22*753557f6STomasz Sapeta     notifyListeners();
23*753557f6STomasz Sapeta   } else {
24*753557f6STomasz Sapeta     runtimeManager->scheduler->scheduleOnUI(
25*753557f6STomasz Sapeta         [notifyListeners] { notifyListeners(); });
26*753557f6STomasz Sapeta   }
27*753557f6STomasz Sapeta }
28*753557f6STomasz Sapeta 
getValue(jsi::Runtime & rt)29*753557f6STomasz Sapeta jsi::Value MutableValue::getValue(jsi::Runtime &rt) {
30*753557f6STomasz Sapeta   std::lock_guard<std::mutex> lock(readWriteMutex);
31*753557f6STomasz Sapeta   return value->getValue(rt);
32*753557f6STomasz Sapeta }
33*753557f6STomasz Sapeta 
set(jsi::Runtime & rt,const jsi::PropNameID & name,const jsi::Value & newValue)34*753557f6STomasz Sapeta void MutableValue::set(
35*753557f6STomasz Sapeta     jsi::Runtime &rt,
36*753557f6STomasz Sapeta     const jsi::PropNameID &name,
37*753557f6STomasz Sapeta     const jsi::Value &newValue) {
38*753557f6STomasz Sapeta   auto propName = name.utf8(rt);
39*753557f6STomasz Sapeta   if (!runtimeManager->valueSetter) {
40*753557f6STomasz Sapeta     throw jsi::JSError(
41*753557f6STomasz Sapeta         rt,
42*753557f6STomasz Sapeta         "Value-Setter is not yet configured! Make sure the core-functions are installed.");
43*753557f6STomasz Sapeta   }
44*753557f6STomasz Sapeta 
45*753557f6STomasz Sapeta   if (RuntimeDecorator::isUIRuntime(rt)) {
46*753557f6STomasz Sapeta     // UI thread
47*753557f6STomasz Sapeta     if (propName == "value") {
48*753557f6STomasz Sapeta       auto setterProxy = jsi::Object::createFromHostObject(
49*753557f6STomasz Sapeta           rt, std::make_shared<MutableValueSetterProxy>(shared_from_this()));
50*753557f6STomasz Sapeta       runtimeManager->valueSetter->getValue(rt)
51*753557f6STomasz Sapeta           .asObject(rt)
52*753557f6STomasz Sapeta           .asFunction(rt)
53*753557f6STomasz Sapeta           .callWithThis(rt, setterProxy, newValue);
54*753557f6STomasz Sapeta     } else if (propName == "_animation") {
55*753557f6STomasz Sapeta       // TODO: assert to allow animation to be set from UI only
56*753557f6STomasz Sapeta       if (animation.expired()) {
57*753557f6STomasz Sapeta         animation = getWeakRef(rt);
58*753557f6STomasz Sapeta       }
59*753557f6STomasz Sapeta       *animation.lock() = jsi::Value(rt, newValue);
60*753557f6STomasz Sapeta     } else if (propName == "_value") {
61*753557f6STomasz Sapeta       auto setter =
62*753557f6STomasz Sapeta           std::make_shared<MutableValueSetterProxy>(shared_from_this());
63*753557f6STomasz Sapeta       setter->set(rt, jsi::PropNameID::forAscii(rt, "_value"), newValue);
64*753557f6STomasz Sapeta     }
65*753557f6STomasz Sapeta   } else {
66*753557f6STomasz Sapeta     // ABI47_0_0React-JS Thread or another threaded Runtime.
67*753557f6STomasz Sapeta     if (propName == "value") {
68*753557f6STomasz Sapeta       auto shareable = ShareableValue::adapt(rt, newValue, runtimeManager);
69*753557f6STomasz Sapeta       runtimeManager->scheduler->scheduleOnUI([this, shareable] {
70*753557f6STomasz Sapeta         jsi::Runtime &rt = *this->runtimeManager->runtime.get();
71*753557f6STomasz Sapeta         auto setterProxy = jsi::Object::createFromHostObject(
72*753557f6STomasz Sapeta             rt, std::make_shared<MutableValueSetterProxy>(shared_from_this()));
73*753557f6STomasz Sapeta         jsi::Value newValue = shareable->getValue(rt);
74*753557f6STomasz Sapeta         runtimeManager->valueSetter->getValue(rt)
75*753557f6STomasz Sapeta             .asObject(rt)
76*753557f6STomasz Sapeta             .asFunction(rt)
77*753557f6STomasz Sapeta             .callWithThis(rt, setterProxy, newValue);
78*753557f6STomasz Sapeta       });
79*753557f6STomasz Sapeta     }
80*753557f6STomasz Sapeta   }
81*753557f6STomasz Sapeta }
82*753557f6STomasz Sapeta 
get(jsi::Runtime & rt,const jsi::PropNameID & name)83*753557f6STomasz Sapeta jsi::Value MutableValue::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
84*753557f6STomasz Sapeta   auto propName = name.utf8(rt);
85*753557f6STomasz Sapeta 
86*753557f6STomasz Sapeta   if (propName == "value") {
87*753557f6STomasz Sapeta     return getValue(rt);
88*753557f6STomasz Sapeta   }
89*753557f6STomasz Sapeta 
90*753557f6STomasz Sapeta   if (RuntimeDecorator::isUIRuntime(rt)) {
91*753557f6STomasz Sapeta     // _value and _animation should be accessed from UI only
92*753557f6STomasz Sapeta     if (propName == "_value") {
93*753557f6STomasz Sapeta       return getValue(rt);
94*753557f6STomasz Sapeta     } else if (propName == "_animation") {
95*753557f6STomasz Sapeta       // TODO: assert to allow animation to be read from UI only
96*753557f6STomasz Sapeta       if (animation.expired()) {
97*753557f6STomasz Sapeta         animation = getWeakRef(rt);
98*753557f6STomasz Sapeta       }
99*753557f6STomasz Sapeta       return jsi::Value(rt, *(animation.lock()));
100*753557f6STomasz Sapeta     }
101*753557f6STomasz Sapeta   }
102*753557f6STomasz Sapeta 
103*753557f6STomasz Sapeta   return jsi::Value::undefined();
104*753557f6STomasz Sapeta }
105*753557f6STomasz Sapeta 
getPropertyNames(jsi::Runtime & rt)106*753557f6STomasz Sapeta std::vector<jsi::PropNameID> MutableValue::getPropertyNames(jsi::Runtime &rt) {
107*753557f6STomasz Sapeta   std::vector<jsi::PropNameID> result;
108*753557f6STomasz Sapeta   result.push_back(jsi::PropNameID::forUtf8(rt, std::string("value")));
109*753557f6STomasz Sapeta   return result;
110*753557f6STomasz Sapeta }
111*753557f6STomasz Sapeta 
MutableValue(jsi::Runtime & rt,const jsi::Value & initial,RuntimeManager * runtimeManager,std::shared_ptr<Scheduler> s)112*753557f6STomasz Sapeta MutableValue::MutableValue(
113*753557f6STomasz Sapeta     jsi::Runtime &rt,
114*753557f6STomasz Sapeta     const jsi::Value &initial,
115*753557f6STomasz Sapeta     RuntimeManager *runtimeManager,
116*753557f6STomasz Sapeta     std::shared_ptr<Scheduler> s)
117*753557f6STomasz Sapeta     : StoreUser(s, *runtimeManager),
118*753557f6STomasz Sapeta       runtimeManager(runtimeManager),
119*753557f6STomasz Sapeta       value(ShareableValue::adapt(rt, initial, runtimeManager)) {}
120*753557f6STomasz Sapeta 
addListener(unsigned long id,std::function<void ()> listener)121*753557f6STomasz Sapeta unsigned long int MutableValue::addListener(
122*753557f6STomasz Sapeta     unsigned long id,
123*753557f6STomasz Sapeta     std::function<void()> listener) {
124*753557f6STomasz Sapeta   listeners[id] = listener;
125*753557f6STomasz Sapeta   return id;
126*753557f6STomasz Sapeta }
127*753557f6STomasz Sapeta 
removeListener(unsigned long listenerId)128*753557f6STomasz Sapeta void MutableValue::removeListener(unsigned long listenerId) {
129*753557f6STomasz Sapeta   if (listeners.count(listenerId) > 0) {
130*753557f6STomasz Sapeta     listeners.erase(listenerId);
131*753557f6STomasz Sapeta   }
132*753557f6STomasz Sapeta }
133*753557f6STomasz Sapeta 
134*753557f6STomasz Sapeta } // namespace reanimated
135