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