convert AnimatedModule away from lambdas (#51659)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/51659

changelog: [internal]

use std::variant in AnimatedModule to generate smaller C++ binary.

Reviewed By: javache, mdvacca

Differential Revision: D75379819

fbshipit-source-id: 4dc8bbf6e2cdb7aa9080a27526ca9d43d155b5d7
This commit is contained in:
Samuel Susla
2025-05-29 05:43:10 -07:00
committed by Facebook GitHub Bot
parent d626d5b623
commit 014f212bce
2 changed files with 223 additions and 130 deletions
@@ -26,17 +26,21 @@ void AnimatedModule::finishOperationBatch(jsi::Runtime& /*rt*/) {
std::vector<Operation> operations;
std::swap(preOperations_, preOperations);
std::swap(operations_, operations);
scheduleOperationOnUI([preOperations = std::move(preOperations),
operations = std::move(operations)](
NativeAnimatedNodesManager& nodesManager) {
for (auto& preOperation : preOperations) {
preOperation(nodesManager);
}
for (auto& operation : operations) {
operation(nodesManager);
}
});
if (nodesManager_) {
// TODO: nodesManager_ must exist at all times. But without this check
// AnimatedProps-itest.js fails.
nodesManager_->scheduleOnUI([this,
preOperations = std::move(preOperations),
operations = std::move(operations)]() {
for (auto& preOperation : preOperations) {
executeOperation(preOperation);
}
for (auto& operation : operations) {
executeOperation(operation);
}
});
}
}
void AnimatedModule::createAnimatedNode(
@@ -44,10 +48,8 @@ void AnimatedModule::createAnimatedNode(
Tag tag,
jsi::Object config) {
auto configDynamic = dynamicFromValue(rt, jsi::Value(rt, config));
addOperation([tag, configDynamic = std::move(configDynamic)](
NativeAnimatedNodesManager& nodesManager) {
nodesManager.createAnimatedNode(tag, configDynamic);
});
operations_.emplace_back(
CreateAnimatedNodeOp{.tag = tag, .config = std::move(configDynamic)});
}
void AnimatedModule::updateAnimatedNodeConfig(
@@ -60,64 +62,37 @@ void AnimatedModule::updateAnimatedNodeConfig(
void AnimatedModule::getValue(
jsi::Runtime& /*rt*/,
Tag tag,
const AsyncCallback<double>& saveValueCallback) {
addOperation([tag,
saveValueCallback,
weakJsInvoker = std::weak_ptr<CallInvoker>(jsInvoker_)](
NativeAnimatedNodesManager& nodesManager) {
auto animValue = nodesManager.getValue(tag);
auto jsInvoker = weakJsInvoker.lock();
if (animValue && jsInvoker) {
jsInvoker->invokeAsync(
[animValue, saveValueCallback = saveValueCallback]() {
saveValueCallback.call(animValue.value());
});
};
});
AsyncCallback<double> saveValueCallback) {
operations_.emplace_back(
GetValueOp{.tag = tag, .callback = std::move(saveValueCallback)});
}
void AnimatedModule::startListeningToAnimatedNodeValue(
jsi::Runtime& /*rt*/,
Tag tag) {
addOperation([tag, this](NativeAnimatedNodesManager& nodesManager) {
nodesManager.startListeningToAnimatedNodeValue(
tag, [this, tag](double value) {
emitDeviceEvent(
"onAnimatedValueUpdate",
[tag, value](jsi::Runtime& rt, std::vector<jsi::Value>& args) {
auto arg = jsi::Object(rt);
arg.setProperty(rt, "tag", jsi::Value(tag));
arg.setProperty(rt, "value", jsi::Value(value));
args.emplace_back(rt, arg);
});
});
});
operations_.emplace_back(StartListeningToAnimatedNodeValueOp{tag});
}
void AnimatedModule::stopListeningToAnimatedNodeValue(
jsi::Runtime& /*rt*/,
Tag tag) {
addOperation([tag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.stopListeningToAnimatedNodeValue(tag);
});
operations_.emplace_back(StopListeningToAnimatedNodeValueOp{tag});
}
void AnimatedModule::connectAnimatedNodes(
jsi::Runtime& /*rt*/,
Tag parentTag,
Tag childTag) {
addOperation([parentTag, childTag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.connectAnimatedNodes(parentTag, childTag);
});
operations_.emplace_back(
ConnectAnimatedNodesOp{.parentTag = parentTag, .childTag = childTag});
}
void AnimatedModule::disconnectAnimatedNodes(
jsi::Runtime& /*rt*/,
Tag parentTag,
Tag childTag) {
addOperation([parentTag, childTag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.disconnectAnimatedNodes(parentTag, childTag);
});
operations_.emplace_back(
DisconnectAnimatedNodesOp{.parentTag = parentTag, .childTag = childTag});
}
void AnimatedModule::startAnimatingNode(
@@ -127,48 +102,40 @@ void AnimatedModule::startAnimatingNode(
jsi::Object config,
AnimationEndCallback endCallback) {
auto configDynamic = dynamicFromValue(rt, jsi::Value(rt, config));
addOperation([animationId,
nodeTag,
configDynamic = std::move(configDynamic),
endCallback = std::move(endCallback)](
NativeAnimatedNodesManager& nodesManager) {
nodesManager.startAnimatingNode(
animationId, nodeTag, configDynamic, endCallback);
});
operations_.emplace_back(StartAnimatingNodeOp{
.animationId = animationId,
.nodeTag = nodeTag,
.config = std::move(configDynamic),
.endCallback = std::move(endCallback)});
}
void AnimatedModule::stopAnimation(jsi::Runtime& /*rt*/, int animationId) {
addOperation([animationId](NativeAnimatedNodesManager& nodesManager) {
nodesManager.stopAnimation(
animationId, false /* TODO: isTrackingAnimation */);
});
operations_.emplace_back(StopAnimationOp{animationId});
}
void AnimatedModule::setAnimatedNodeValue(
jsi::Runtime& /*rt*/,
Tag nodeTag,
double value) {
addOperation([nodeTag, value](NativeAnimatedNodesManager& nodesManager) {
nodesManager.setAnimatedNodeValue(nodeTag, value);
});
operations_.emplace_back(SetAnimatedNodeValueOp{nodeTag, value});
}
void AnimatedModule::setAnimatedNodeOffset(
jsi::Runtime& /*rt*/,
Tag nodeTag,
double offset) {
Tag /*nodeTag*/,
double /*offset*/) {
// TODO: missing implementation
}
void AnimatedModule::flattenAnimatedNodeOffset(
jsi::Runtime& /*rt*/,
Tag nodeTag) {
Tag /*nodeTag*/) {
// TODO: missing implementation
}
void AnimatedModule::extractAnimatedNodeOffset(
jsi::Runtime& /*rt*/,
Tag nodeTag) {
Tag /*nodeTag*/) {
// TODO: missing implementation
}
@@ -176,73 +143,124 @@ void AnimatedModule::connectAnimatedNodeToView(
jsi::Runtime& /*rt*/,
Tag nodeTag,
Tag viewTag) {
addOperation([nodeTag, viewTag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.connectAnimatedNodeToView(nodeTag, viewTag);
});
operations_.emplace_back(ConnectAnimatedNodeToViewOp{nodeTag, viewTag});
}
void AnimatedModule::disconnectAnimatedNodeFromView(
jsi::Runtime& /*rt*/,
Tag nodeTag,
Tag viewTag) {
addOperation([nodeTag, viewTag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.disconnectAnimatedNodeFromView(nodeTag, viewTag);
});
operations_.emplace_back(DisconnectAnimatedNodeFromViewOp{nodeTag, viewTag});
}
void AnimatedModule::restoreDefaultValues(jsi::Runtime& /*rt*/, Tag nodeTag) {
addOperation(
[nodeTag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.restoreDefaultValues(nodeTag);
},
/* preOperation = */ true);
preOperations_.emplace_back(RestoreDefaultValuesOp{nodeTag});
}
void AnimatedModule::dropAnimatedNode(jsi::Runtime& /*rt*/, Tag tag) {
addOperation([tag](NativeAnimatedNodesManager& nodesManager) {
nodesManager.dropAnimatedNode(tag);
});
operations_.emplace_back(DropAnimatedNodeOp{tag});
}
void AnimatedModule::addAnimatedEventToView(
jsi::Runtime& rt,
Tag viewTag,
const std::string& eventName,
std::string eventName,
jsi::Object eventMapping) {
auto eventMappingDynamic = dynamicFromValue(rt, jsi::Value(rt, eventMapping));
addOperation([viewTag, eventName, eventMappingDynamic](
NativeAnimatedNodesManager& nodesManager) {
nodesManager.addAnimatedEventToView(
viewTag, eventName, eventMappingDynamic);
});
operations_.emplace_back(AddAnimatedEventToViewOp{
.viewTag = viewTag,
.eventName = std::move(eventName),
.eventMapping = std::move(eventMappingDynamic)});
}
void AnimatedModule::removeAnimatedEventFromView(
jsi::Runtime& /*rt*/,
Tag viewTag,
const std::string& eventName,
std::string eventName,
Tag animatedNodeTag) {
addOperation([viewTag, eventName, animatedNodeTag](
NativeAnimatedNodesManager& nodesManager) {
nodesManager.removeAnimatedEventFromView(
viewTag, eventName, animatedNodeTag);
});
operations_.emplace_back(RemoveAnimatedEventFromViewOp{
.viewTag = viewTag,
.eventName = std::move(eventName),
.animatedNodeTag = animatedNodeTag});
}
void AnimatedModule::addListener(
jsi::Runtime& rt,
const std::string& eventName) {}
jsi::Runtime& /*rt*/,
const std::string& /*eventName*/) {
// TODO: missing implementation
}
void AnimatedModule::removeListeners(jsi::Runtime& rt, int count) {}
void AnimatedModule::removeListeners(jsi::Runtime& /*rt*/, int /*count*/) {
// TODO: missing implementation
}
void AnimatedModule::queueAndExecuteBatchedOperations(
jsi::Runtime& rt,
jsi::Array operationsAndArgs) {}
jsi::Runtime& /*rt*/,
jsi::Array /*operationsAndArgs*/) {
// TODO: missing implementation
}
void AnimatedModule::addOperation(Operation&& operation, bool preOperation) {
// No mutex needed, operations only added via TurboModule method invocation
auto& queue = preOperation ? preOperations_ : operations_;
queue.push_back(std::move(operation));
void AnimatedModule::executeOperation(const Operation& operation) {
std::visit(
[&](const auto& op) {
using T = std::decay_t<decltype(op)>;
if constexpr (std::is_same_v<T, CreateAnimatedNodeOp>) {
nodesManager_->createAnimatedNode(op.tag, op.config);
} else if constexpr (std::is_same_v<T, GetValueOp>) {
auto animValue = nodesManager_->getValue(op.tag);
if (animValue) {
op.callback.call(animValue.value());
}
} else if constexpr (std::is_same_v<
T,
StartListeningToAnimatedNodeValueOp>) {
nodesManager_->startListeningToAnimatedNodeValue(
op.tag, [this, tag = op.tag](double value) {
emitDeviceEvent(
"onAnimatedValueUpdate",
[tag, value](
jsi::Runtime& rt, std::vector<jsi::Value>& args) {
auto arg = jsi::Object(rt);
arg.setProperty(rt, "tag", jsi::Value(tag));
arg.setProperty(rt, "value", jsi::Value(value));
args.emplace_back(rt, arg);
});
});
} else if constexpr (std::is_same_v<
T,
StopListeningToAnimatedNodeValueOp>) {
nodesManager_->stopListeningToAnimatedNodeValue(op.tag);
} else if constexpr (std::is_same_v<T, ConnectAnimatedNodesOp>) {
nodesManager_->connectAnimatedNodes(op.parentTag, op.childTag);
} else if constexpr (std::is_same_v<T, DisconnectAnimatedNodesOp>) {
nodesManager_->disconnectAnimatedNodes(op.parentTag, op.childTag);
} else if constexpr (std::is_same_v<T, StartAnimatingNodeOp>) {
nodesManager_->startAnimatingNode(
op.animationId, op.nodeTag, op.config, op.endCallback);
} else if constexpr (std::is_same_v<T, StopAnimationOp>) {
nodesManager_->stopAnimation(op.animationId, false);
} else if constexpr (std::is_same_v<T, SetAnimatedNodeValueOp>) {
nodesManager_->setAnimatedNodeValue(op.nodeTag, op.value);
} else if constexpr (std::is_same_v<T, ConnectAnimatedNodeToViewOp>) {
nodesManager_->connectAnimatedNodeToView(op.nodeTag, op.viewTag);
} else if constexpr (std::is_same_v<
T,
DisconnectAnimatedNodeFromViewOp>) {
nodesManager_->disconnectAnimatedNodeFromView(op.nodeTag, op.viewTag);
} else if constexpr (std::is_same_v<T, RestoreDefaultValuesOp>) {
nodesManager_->restoreDefaultValues(op.nodeTag);
} else if constexpr (std::is_same_v<T, DropAnimatedNodeOp>) {
nodesManager_->dropAnimatedNode(op.tag);
} else if constexpr (std::is_same_v<T, AddAnimatedEventToViewOp>) {
nodesManager_->addAnimatedEventToView(
op.viewTag, op.eventName, op.eventMapping);
} else if constexpr (std::is_same_v<T, RemoveAnimatedEventFromViewOp>) {
nodesManager_->removeAnimatedEventFromView(
op.viewTag, op.eventName, op.animatedNodeTag);
}
},
operation);
}
void AnimatedModule::installJSIBindingsWithRuntime(jsi::Runtime& runtime) {
@@ -9,18 +9,111 @@
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <ReactCommon/TurboModuleWithJSIBindings.h>
#include <folly/dynamic.h>
#include <react/renderer/animated/NativeAnimatedNodesManager.h>
#include <react/renderer/animated/NativeAnimatedNodesManagerProvider.h>
#include <react/renderer/core/ReactPrimitives.h>
#include <memory>
#include <string>
#include <variant>
namespace facebook::react {
class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>,
public TurboModuleWithJSIBindings {
using Operation =
std::function<void(NativeAnimatedNodesManager& nodesManager)>;
#pragma mark - Operation structures for each type of animated operation
struct CreateAnimatedNodeOp {
Tag tag{};
folly::dynamic config;
};
struct GetValueOp {
Tag tag{};
AsyncCallback<double> callback;
};
struct StartListeningToAnimatedNodeValueOp {
Tag tag{};
};
struct StopListeningToAnimatedNodeValueOp {
Tag tag{};
};
struct ConnectAnimatedNodesOp {
Tag parentTag{};
Tag childTag{};
};
struct DisconnectAnimatedNodesOp {
Tag parentTag{};
Tag childTag{};
};
struct StartAnimatingNodeOp {
int animationId{};
Tag nodeTag{};
folly::dynamic config;
AnimationEndCallback endCallback;
};
struct StopAnimationOp {
int animationId{};
};
struct SetAnimatedNodeValueOp {
Tag nodeTag{};
double value{};
};
struct ConnectAnimatedNodeToViewOp {
Tag nodeTag{};
Tag viewTag{};
};
struct DisconnectAnimatedNodeFromViewOp {
Tag nodeTag{};
Tag viewTag{};
};
struct RestoreDefaultValuesOp {
Tag nodeTag{};
};
struct DropAnimatedNodeOp {
Tag tag{};
};
struct AddAnimatedEventToViewOp {
Tag viewTag{};
std::string eventName;
folly::dynamic eventMapping;
};
struct RemoveAnimatedEventFromViewOp {
Tag viewTag{};
std::string eventName;
Tag animatedNodeTag{};
};
using Operation = std::variant<
CreateAnimatedNodeOp,
GetValueOp,
StartListeningToAnimatedNodeValueOp,
StopListeningToAnimatedNodeValueOp,
ConnectAnimatedNodesOp,
DisconnectAnimatedNodesOp,
StartAnimatingNodeOp,
StopAnimationOp,
SetAnimatedNodeValueOp,
ConnectAnimatedNodeToViewOp,
DisconnectAnimatedNodeFromViewOp,
RestoreDefaultValuesOp,
DropAnimatedNodeOp,
AddAnimatedEventToViewOp,
RemoveAnimatedEventFromViewOp>;
#pragma mark -
public:
AnimatedModule(
@@ -35,10 +128,8 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>,
void updateAnimatedNodeConfig(jsi::Runtime& rt, Tag tag, jsi::Object config);
void getValue(
jsi::Runtime& rt,
Tag tag,
const AsyncCallback<double>& saveValueCallback);
void
getValue(jsi::Runtime& rt, Tag tag, AsyncCallback<double> saveValueCallback);
void startListeningToAnimatedNodeValue(jsi::Runtime& rt, Tag tag);
@@ -77,13 +168,13 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>,
void addAnimatedEventToView(
jsi::Runtime& rt,
Tag viewTag,
const std::string& eventName,
std::string eventName,
jsi::Object eventMapping);
void removeAnimatedEventFromView(
jsi::Runtime& rt,
Tag viewTag,
const std::string& eventName,
std::string eventName,
Tag animatedNodeTag);
void addListener(jsi::Runtime& rt, const std::string& eventName);
@@ -94,29 +185,13 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>,
jsi::Runtime& rt,
jsi::Array operationsAndArgs);
void scheduleOperationOnUI(Operation&& fn) {
if (nodesManager_) {
nodesManager_->scheduleOnUI(
[fn = std::move(fn),
weakNodesManager =
std::weak_ptr<NativeAnimatedNodesManager>(nodesManager_)]() {
if (auto nodesManager = weakNodesManager.lock()) {
fn(*nodesManager);
}
});
}
}
protected:
std::shared_ptr<NativeAnimatedNodesManagerProvider> nodesManagerProvider_;
private:
std::shared_ptr<NativeAnimatedNodesManagerProvider> nodesManagerProvider_;
std::shared_ptr<NativeAnimatedNodesManager> nodesManager_;
std::vector<Operation> preOperations_;
std::vector<Operation> operations_;
void addOperation(Operation&& operation, bool preOperation = false);
void executeOperation(const Operation& operation);
void installJSIBindingsWithRuntime(jsi::Runtime& runtime) override;
};