This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,4 @@
#import "REANode.h"
@interface REAAlwaysNode : REANode <REAFinalNode>
@end

View File

@ -0,0 +1,36 @@
#import "REAAlwaysNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import "REAStyleNode.h"
#import "REAModule.h"
#import <React/RCTLog.h>
#import <React/RCTConvert.h>
#import <React/RCTUIManager.h>
@implementation REAAlwaysNode
{
NSNumber * _nodeToBeEvaluated;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_nodeToBeEvaluated = [RCTConvert NSNumber:config[@"what"]];
REA_LOG_ERROR_IF_NIL(_nodeToBeEvaluated, @"Reanimated: First argument passed to always node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
[[self.nodesManager findNodeByID:_nodeToBeEvaluated] value];
return @(0);
}
- (void)update
{
[self value];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REABezierNode : REANode
@end

View File

@ -0,0 +1,103 @@
#include <tgmath.h>
#import "REABezierNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#define EPS 1e-5
@implementation REABezierNode {
CGFloat ax, bx, cx, ay, by, cy;
NSNumber *_inputNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_inputNodeID = [RCTConvert NSNumber:config[@"input"]];
REA_LOG_ERROR_IF_NIL(_inputNodeID, @"Reanimated: First argument passed to bezier node is either of wrong type or is missing.");
CGFloat mX1 = [config[@"mX1"] doubleValue];
CGFloat mY1 = [config[@"mY1"] doubleValue];
CGFloat mX2 = [config[@"mX2"] doubleValue];
CGFloat mY2 = [config[@"mY2"] doubleValue];
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
cx = 3.0 * mX1;
bx = 3.0 * (mX2 - mX1) - cx;
ax = 1.0 - cx -bx;
cy = 3.0 * mY1;
by = 3.0 * (mY2 - mY1) - cy;
ay = 1.0 - cy - by;
}
return self;
}
- (CGFloat)sampleCurveX:(CGFloat)t
{
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
return ((ax * t + bx) * t + cx) * t;
}
- (CGFloat)sampleCurveY:(CGFloat)t
{
return ((ay * t + by) * t + cy) * t;
}
- (CGFloat)sampleCurveDerivativeX:(CGFloat)t
{
return (3.0 * ax * t + 2.0 * bx) * t + cx;
}
- (CGFloat)solveCurveX:(CGFloat)x withEpsilon:(CGFloat)epsilon
{
CGFloat t0, t1, t2, x2, d2;
NSUInteger i;
// First try a few iterations of Newton's method -- normally very fast.
for (t2 = x, i = 0; i < 8; i++) {
x2 = [self sampleCurveX:t2] - x;
if (fabs (x2) < epsilon)
return t2;
d2 = [self sampleCurveDerivativeX:t2];
if (fabs(d2) < 1e-6)
break;
t2 = t2 - x2 / d2;
}
// Fall back to the bisection method for reliability.
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1) {
x2 = [self sampleCurveX:t2];
if (fabs(x2 - x) < epsilon)
return t2;
if (x > x2)
t0 = t2;
else
t1 = t2;
t2 = (t1 - t0) * .5 + t0;
}
// Failure.
return t2;
}
- (id)evaluate
{
CGFloat x = [[[self.nodesManager findNodeByID:_inputNodeID] value] doubleValue];
CGFloat y = [self sampleCurveY:[self solveCurveX:x withEpsilon:EPS]];
return @(y);
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REABlockNode : REANode
@end

View File

@ -0,0 +1,25 @@
#import "REABlockNode.h"
#import "REANodesManager.h"
@implementation REABlockNode {
NSArray<NSNumber *> *_block;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_block = config[@"block"];
}
return self;
}
- (id)evaluate
{
id result;
for (NSNumber *inputID in _block) {
result = [[self.nodesManager findNodeByID:inputID] value];
}
return result;
}
@end

View File

@ -0,0 +1,7 @@
#import "REANode.h"
@interface REACallFuncNode : REANode
@end

View File

@ -0,0 +1,67 @@
#import "REACallFuncNode.h"
#import "REAFunctionNode.h"
#import "REAUtils.h"
#import "REAParamNode.h"
#import "REANodesManager.h"
@implementation REACallFuncNode {
NSNumber *_whatNodeID;
NSArray<NSNumber *> *_args;
NSArray<NSNumber *> *_params;
NSString* _prevCallID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_whatNodeID = config[@"what"];
REA_LOG_ERROR_IF_NIL(_whatNodeID, @"Reanimated: First argument passed to callFunc node is either of wrong type or is missing.");
_args = config[@"args"];
_params = config[@"params"];
_prevCallID = NULL;
}
return self;
}
- (void)beginContext
{
// To ensure that functions can be called multiple times in the same animation frame
// (functions might have different parameters and might be called multiple times)
// we inform the current update context about where we are called from by setting the
// current call id - this will ensure that memoization is correct for function nodes.
_prevCallID = self.updateContext.callID;
self.updateContext.callID = [NSString stringWithFormat:@"%@/%@", self.updateContext.callID, [self.nodeID stringValue]];
// A CallFuncNode has a reference to a function node which holds the node graph that should
// be updated. A Function node has a list of ParamNodes which are basically nodes that can
// reference other nodes. When we start a new function call we update the parameter nodes
// with the current arguments:
for (NSUInteger i = 0; i < _params.count; i++) {
NSNumber *paramID = [_params objectAtIndex:i];
REAParamNode *param = (REAParamNode *)[self.nodesManager findNodeByID:paramID];
[param beginContext:_args[i] prevCallID:_prevCallID];
}
}
- (void)endContext
{
for (NSUInteger i = 0; i < _params.count; i++) {
NSNumber *paramID = [_params objectAtIndex:i];
REAParamNode *param = (REAParamNode *)[self.nodesManager findNodeByID:paramID];
[param endContext];
}
self.updateContext.callID = _prevCallID;
}
- (id)evaluate
{
[self beginContext];
REAFunctionNode *what = (REAFunctionNode *)[self.nodesManager findNodeByID:_whatNodeID];
NSNumber *newValue = [what value];
[self endContext];
return newValue;
}
@end

View File

@ -0,0 +1,19 @@
#import "REANode.h"
@interface REAClockNode : REANode
@property (nonatomic, readonly) BOOL isRunning;
- (void)start;
- (void)stop;
@end
@interface REAClockOpNode : REANode
@end
@interface REAClockStartNode : REAClockOpNode
@end
@interface REAClockStopNode : REAClockOpNode
@end
@interface REAClockTestNode : REAClockOpNode
@end

View File

@ -0,0 +1,116 @@
#import "REAClockNodes.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import "REAParamNode.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
@interface REAClockNode ()
@property (nonatomic) NSNumber *lastTimestampMs;
@end
@implementation REAClockNode
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_isRunning = NO;
}
return self;
}
- (void)start
{
if (_isRunning) return;
_isRunning = YES;
__block __weak void (^weak_animationClb)(CADisplayLink *displayLink);
void (^animationClb)(CADisplayLink *displayLink);
__weak REAClockNode *weakSelf = self;
weak_animationClb = animationClb = ^(CADisplayLink *displayLink) {
if (!weakSelf.isRunning) return;
[weakSelf markUpdated];
[weakSelf.nodesManager postOnAnimation:weak_animationClb];
};
[self.nodesManager postOnAnimation:animationClb];
}
- (void)stop
{
_isRunning = false;
}
- (id)evaluate
{
return @(self.nodesManager.currentAnimationTimestamp * 1000.);
}
@end
@implementation REAClockOpNode {
NSNumber *_clockNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_clockNodeID = [RCTConvert NSNumber:config[@"clock"]];
REA_LOG_ERROR_IF_NIL(_clockNodeID, @"Reanimated: First argument passed to clock node is either of wrong type or is missing.");
}
return self;
}
- (REANode*)clockNode
{
return (REANode*)[self.nodesManager findNodeByID:_clockNodeID];
}
@end
@implementation REAClockStartNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node start];
} else {
[(REAClockNode* )node start];
}
return @(0);
}
@end
@implementation REAClockStopNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node stop];
} else {
[(REAClockNode* )node stop];
}
return @(0);
}
@end
@implementation REAClockTestNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
return @(((REAParamNode* )node).isRunning ? 1 : 0);
}
return @([(REAClockNode* )node isRunning] ? 1 : 0);
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REAConcatNode : REANode
@end

View File

@ -0,0 +1,32 @@
#import "REAConcatNode.h"
#import "REAValueNode.h"
#import "REANodesManager.h"
@implementation REAConcatNode {
NSArray<NSNumber *> *_input;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
}
return self;
}
- (id)evaluate
{
NSMutableString *result = [NSMutableString new];
for (int i = 0; i < _input.count; i++) {
NSObject *val = [[self.nodesManager findNodeByID:_input[i]] value];
if ([val isKindOfClass:[NSNumber class]]) {
[result appendString:[(NSNumber *)val stringValue]];
}
if ([val isKindOfClass:[NSString class]]) {
[result appendString:val];
}
}
return result;
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REACondNode : REANode
@end

View File

@ -0,0 +1,34 @@
#import "REACondNode.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import "REAUtils.h"
#import <React/RCTLog.h>
@implementation REACondNode {
NSNumber *_condNodeID;
NSNumber *_ifBlockID;
NSNumber *_elseBlockID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_condNodeID = [RCTConvert NSNumber:config[@"cond"]];
REA_LOG_ERROR_IF_NIL(_condNodeID, @"Reanimated: First argument passed to cond node is either of wrong type or is missing.");
_ifBlockID = [RCTConvert NSNumber:config[@"ifBlock"]];
REA_LOG_ERROR_IF_NIL(_ifBlockID, @"Reanimated: Second argument passed to cond node is either of wrong type or is missing.");
_elseBlockID = [RCTConvert NSNumber:config[@"elseBlock"]];
}
return self;
}
- (id)evaluate
{
id cond = [[self.nodesManager findNodeByID:_condNodeID] value];
if ([cond doubleValue]) {
return [[self.nodesManager findNodeByID:_ifBlockID] value];
}
return _elseBlockID != nil ? [[self.nodesManager findNodeByID:_elseBlockID] value] : @(0);
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface READebugNode : REANode
@end

View File

@ -0,0 +1,29 @@
#import "READebugNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
@implementation READebugNode {
NSNumber *_valueNodeID;
NSString *_message;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_message = [RCTConvert NSString:config[@"message"]];
_valueNodeID = [RCTConvert NSNumber:config[@"value"]];
REA_LOG_ERROR_IF_NIL(_valueNodeID, @"Reanimated: Second argument passed to debug node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
id value = [[self.nodesManager findNodeByID:_valueNodeID] value];
NSLog(@"%@ %@", _message, value);
return value;
}
@end

View File

@ -0,0 +1,9 @@
#import "REANode.h"
#import <React/RCTEventDispatcher.h>
@interface REAEventNode : REANode
- (void)processEvent:(id<RCTEvent>)event;
@end

View File

@ -0,0 +1,35 @@
#import "REAEventNode.h"
#import "REANodesManager.h"
#import "REAValueNode.h"
@implementation REAEventNode {
NSArray *_argMapping;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_argMapping = config[@"argMapping"];
}
return self;
}
- (void)processEvent:(id<RCTEvent>)event
{
NSArray *args = event.arguments;
// argMapping is an array of eventPaths, each even path ends with a target node ID
for (NSArray *eventPath in _argMapping) {
// Supported events args are in the following order: viewTag, eventName, eventData.
id value = args[2];
for (NSUInteger i = 0; i < eventPath.count; i++) {
if (i < eventPath.count - 1) {
value = [value valueForKey:eventPath[i]];
} else {
REAValueNode *node = (REAValueNode *)[self.nodesManager findNodeByID:eventPath[i]];
[node setValue:value];
}
}
}
}
@end

View File

@ -0,0 +1,7 @@
#import "REANode.h"
@interface REAFunctionNode : REANode
@end

View File

@ -0,0 +1,24 @@
#import "REAFunctionNode.h"
#import "REAParamNode.h"
#import "REANodesManager.h"
@implementation REAFunctionNode {
NSNumber *_nodeToBeEvaluated;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_nodeToBeEvaluated = config[@"what"];
}
return self;
}
- (id)evaluate
{
REANode *node = [self.nodesManager findNodeByID:_nodeToBeEvaluated];
return [node value];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REAJSCallNode : REANode
@end

View File

@ -0,0 +1,31 @@
#import "REAJSCallNode.h"
#import "REANodesManager.h"
#import "REAModule.h"
@implementation REAJSCallNode {
NSArray<NSNumber *> *_input;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
}
return self;
}
- (id)evaluate
{
NSMutableArray *args = [NSMutableArray arrayWithCapacity:_input.count];
for (NSUInteger i = 0; i < _input.count; i++) {
args[i] = [[self.nodesManager findNodeByID:_input[i]] value];
}
[self.nodesManager.reanimatedModule
sendEventWithName:@"onReanimatedCall"
body:@{@"id": self.nodeID, @"args": args }];
return @(0);
}
@end

View File

@ -0,0 +1,39 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class REANodesManager;
typedef NSNumber* REANodeID;
@protocol REAFinalNode
- (void)update;
@end
@interface REAUpdateContext : NSObject
@property (nonatomic) NSString* callID;
@end
@interface REANode : NSObject
+ (void)runPropUpdates:(nonnull REAUpdateContext *)context;
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config NS_DESIGNATED_INITIALIZER;
@property (nonatomic, weak, nullable) REANodesManager *nodesManager;
@property (nonatomic, nullable) REAUpdateContext *updateContext;
@property (nonatomic, readonly, nonnull) REANodeID nodeID;
- (_Nullable id)evaluate;
- (_Nullable id)value;
- (void)markUpdated;
- (void)addChild:(REANode *)child NS_REQUIRES_SUPER;
- (void)removeChild:(REANode *)child NS_REQUIRES_SUPER;
- (void)dangerouslyRescheduleEvaluate;
- (void)forceUpdateMemoizedValue:(id)value;
@end

View File

@ -0,0 +1,152 @@
#import "REANode.h"
#import "REANodesManager.h"
#import <React/RCTDefines.h>
@interface REAUpdateContext ()
@property (nonatomic, nonnull) NSMutableArray<REANode *> *updatedNodes;
@property (nonatomic) NSNumber* loopID;
@end
@implementation REAUpdateContext
- (instancetype)init
{
if ((self = [super init])) {
_loopID = [[NSNumber alloc] initWithInt:1];
_updatedNodes = [NSMutableArray new];
_callID = @"";
}
return self;
}
@end
@interface REANode ()
@property (nonatomic) NSMutableDictionary<REANodeID, NSNumber*>* lastLoopID;
@property (nonatomic) NSMutableDictionary<REANodeID, id>* memoizedValue;
@property (nonatomic, nullable) NSMutableArray<REANode *> *childNodes;
@end
@implementation REANode
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super init])) {
_nodeID = nodeID;
_lastLoopID = [NSMutableDictionary dictionary];
_memoizedValue = [NSMutableDictionary dictionary];
_lastLoopID[@""] = 0;
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)init)
- (void)dangerouslyRescheduleEvaluate
{
_lastLoopID[self.updateContext.callID] = 0;
[self markUpdated];
}
- (void)forceUpdateMemoizedValue:(id)value
{
_memoizedValue[self.updateContext.callID] = value;
[self markUpdated];
}
- (id)evaluate
{
return 0;
}
- (id)value
{
if (![_lastLoopID objectForKey:_updateContext.callID] || [[_lastLoopID objectForKey:_updateContext.callID] longValue] < [_updateContext.loopID longValue]) {
[_lastLoopID setObject:_updateContext.loopID forKey:_updateContext.callID];
id val = [self evaluate];
[_memoizedValue setObject:(val == nil ? [NSNull null] : val) forKey:_updateContext.callID];
return val;
}
id memoizedValue = [_memoizedValue objectForKey:_updateContext.callID];
return [memoizedValue isKindOfClass:[NSNull class]] ? nil : memoizedValue;
}
- (void)addChild:(REANode *)child
{
if (!_childNodes) {
_childNodes = [NSMutableArray new];
}
if (child) {
[_childNodes addObject:child];
[child dangerouslyRescheduleEvaluate];
}
}
- (void)removeChild:(REANode *)child
{
if (child) {
[_childNodes removeObject:child];
}
}
- (void)markUpdated
{
[_updateContext.updatedNodes addObject:self];
[self.nodesManager postRunUpdatesAfterAnimation];
}
+ (NSMutableArray<REANode *> *)updatedNodes
{
static NSMutableArray<REANode *> *updatedNodes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
updatedNodes = [NSMutableArray new];
});
return updatedNodes;
}
+ (void)findAndUpdateNodes:(nonnull REANode *)node
withVisitedSet:(NSMutableSet<REANode *> *)visitedNodes
withFinalNodes:(NSMutableArray<id<REAFinalNode>> *)finalNodes
{
if ([visitedNodes containsObject:node]) {
return;
} else {
[visitedNodes addObject:node];
}
for (REANode *child in node.childNodes) {
[self findAndUpdateNodes:child withVisitedSet:visitedNodes withFinalNodes:finalNodes];
}
if ([node conformsToProtocol:@protocol(REAFinalNode)]) {
[finalNodes addObject:(id<REAFinalNode>)node];
}
}
+ (void)runPropUpdates:(REAUpdateContext *)context
{
NSMutableSet<REANode *> *visitedNodes = [NSMutableSet new];
NSMutableArray<id<REAFinalNode>> *finalNodes = [NSMutableArray new];
for (NSUInteger i = 0; i < context.updatedNodes.count; i++) {
[self findAndUpdateNodes:context.updatedNodes[i]
withVisitedSet:visitedNodes
withFinalNodes:finalNodes];
if (i == context.updatedNodes.count - 1) {
while (finalNodes.count > 0) {
// NSMutableArray used for stack implementation
[[finalNodes lastObject] update];
[finalNodes removeLastObject];
}
}
}
[context.updatedNodes removeAllObjects];
context.loopID = [[NSNumber alloc] initWithLong:context.loopID.longValue + 1];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REAOperatorNode : REANode
@end

View File

@ -0,0 +1,114 @@
#include <tgmath.h>
#import "REAOperatorNode.h"
#import "REANodesManager.h"
typedef id (^REAOperatorBlock)(NSArray<REANode *> *inputNodes);
#define REA_REDUCE(OP) ^(NSArray<REANode *> *inputNodes) { \
double acc = [[inputNodes[0] value] doubleValue]; \
for (NSUInteger i = 1; i < inputNodes.count; i++) { \
double a = acc, b = [[inputNodes[i] value] doubleValue]; \
acc = OP; \
} \
return @(acc); \
}
#define REA_SINGLE(OP) ^(NSArray<REANode *> *inputNodes) { \
double a = [[inputNodes[0] value] doubleValue]; \
return @(OP); \
}
#define REA_INFIX(OP) ^(NSArray<REANode *> *inputNodes) { \
double a = [[inputNodes[0] value] doubleValue]; \
double b = [[inputNodes[1] value] doubleValue]; \
return @(OP); \
}
@implementation REAOperatorNode {
NSArray<NSNumber *> *_input;
NSMutableArray<REANode *> *_inputNodes;
REAOperatorBlock _op;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
static NSDictionary *OPS;
static dispatch_once_t opsToken;
dispatch_once(&opsToken, ^{
OPS = @{
// arithmetic
@"add": REA_REDUCE(a + b),
@"sub": REA_REDUCE(a - b),
@"multiply": REA_REDUCE(a * b),
@"divide": REA_REDUCE(a / b),
@"pow": REA_REDUCE(pow(a, b)),
@"modulo": REA_REDUCE(fmod(fmod(a, b) + b, b)),
@"sqrt": REA_SINGLE(sqrt(a)),
@"log": REA_SINGLE(log(a)),
@"sin": REA_SINGLE(sin(a)),
@"cos": REA_SINGLE(cos(a)),
@"tan": REA_SINGLE(tan(a)),
@"acos": REA_SINGLE(acos(a)),
@"asin": REA_SINGLE(asin(a)),
@"atan": REA_SINGLE(atan(a)),
@"exp": REA_SINGLE(exp(a)),
@"round": REA_SINGLE(round(a)),
@"abs": REA_SINGLE(fabs(a)),
@"ceil": REA_SINGLE(ceil(a)),
@"floor": REA_SINGLE(floor(a)),
@"max": REA_REDUCE(MAX(a, b)),
@"min": REA_REDUCE(MIN(a, b)),
// logical
@"and": ^(NSArray<REANode *> *inputNodes) {
BOOL res = [[inputNodes[0] value] doubleValue];
for (NSUInteger i = 1; i < inputNodes.count && res; i++) {
res = res && [[inputNodes[i] value] doubleValue];
}
return res ? @(1.) : @(0.);
},
@"or": ^(NSArray<REANode *> *inputNodes) {
BOOL res = [[inputNodes[0] value] doubleValue];
for (NSUInteger i = 1; i < inputNodes.count && !res; i++) {
res = res || [[inputNodes[i] value] doubleValue];
}
return res ? @(1.) : @(0.);
},
@"not": REA_SINGLE(!a),
@"defined": ^(NSArray<REANode *> *inputNodes) {
id val = [inputNodes[0] value];
id res = @(val != nil && !([val isKindOfClass:[NSNumber class]] && isnan([val doubleValue])));
return res;
},
// comparing
@"lessThan": REA_INFIX(a < b),
@"eq": REA_INFIX(a == b),
@"greaterThan": REA_INFIX(a > b),
@"lessOrEq": REA_INFIX(a <= b),
@"greaterOrEq": REA_INFIX(a >= b),
@"neq": REA_INFIX(a != b),
};
});
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
_inputNodes = [NSMutableArray arrayWithCapacity:_input.count];
_op = OPS[config[@"op"]];
if (!_op) {
RCTLogError(@"Operator '%@' not found", config[@"op"]);
}
}
return self;
}
- (id)evaluate
{
for (NSUInteger i = 0; i < _input.count; i++) {
_inputNodes[i] = [self.nodesManager findNodeByID:_input[i]];
}
return _op(_inputNodes);
}
@end

View File

@ -0,0 +1,12 @@
#import "REAValueNode.h"
@interface REAParamNode : REAValueNode
- (void)beginContext:(NSNumber*) ref
prevCallID:(NSNumber*) prevCallID;
- (void)endContext;
- (void)start;
- (void)stop;
- (BOOL)isRunning;
@end

View File

@ -0,0 +1,81 @@
#import "REAParamNode.h"
#import "REAValueNode.h"
#import "REANodesManager.h"
#import "REAClockNodes.h"
@implementation REAParamNode {
NSMutableArray<REANodeID> *_argstack;
NSString *_prevCallID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_argstack = [NSMutableArray<REANodeID> arrayWithCapacity:0];
}
return self;
}
- (void)setValue:(NSNumber *)value
{
REANode *node = [self.nodesManager findNodeByID:[_argstack lastObject]];
NSString *callID = self.updateContext.callID;
self.updateContext.callID = _prevCallID;
[(REAValueNode*)node setValue:value];
self.updateContext.callID = callID;
[self forceUpdateMemoizedValue:value];
}
- (void)beginContext:(NSNumber*) ref
prevCallID:(NSString*) prevCallID
{
_prevCallID = prevCallID;
[_argstack addObject:ref];
}
- (void)endContext
{
[_argstack removeLastObject];
}
- (id)evaluate
{
NSString *callID = self.updateContext.callID;
self.updateContext.callID = _prevCallID;
REANode * node = [self.nodesManager findNodeByID:[_argstack lastObject]];
id val = [node value];
self.updateContext.callID = callID;
return val;
}
- (void)start
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node start];
} else {
[(REAClockNode* )node start];
}
}
- (void)stop
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node stop];
} else {
[(REAClockNode* )node stop];
}
}
- (BOOL)isRunning
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
return [(REAParamNode* )node isRunning];
}
return [(REAClockNode* )node isRunning];
}
@end

View File

@ -0,0 +1,11 @@
#import "REANode.h"
@interface REAPropsNode : REANode <REAFinalNode>
- (void)connectToView:(NSNumber *_Nonnull)viewTag
viewName:(NSString *_Nonnull)viewName;
- (void)disconnectFromView:(NSNumber *_Nonnull)viewTag;
@end

View File

@ -0,0 +1,101 @@
#import "REAPropsNode.h"
#import "REANodesManager.h"
#import "REAStyleNode.h"
#import "REAModule.h"
#import <React/RCTLog.h>
#import <React/RCTUIManager.h>
#import "React/RCTComponentData.h"
@implementation REAPropsNode
{
NSNumber *_connectedViewTag;
NSString *_connectedViewName;
NSMutableDictionary<NSString *, REANodeID> *_propsConfig;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *,id> *)config
{
if (self = [super initWithID:nodeID config:config]) {
_propsConfig = config[@"props"];
}
return self;
}
- (void)connectToView:(NSNumber *)viewTag
viewName:(NSString *)viewName
{
_connectedViewTag = viewTag;
_connectedViewName = viewName;
[self dangerouslyRescheduleEvaluate];
}
- (void)disconnectFromView:(NSNumber *)viewTag
{
_connectedViewTag = nil;
_connectedViewName = nil;
}
- (id)evaluate
{
NSMutableDictionary *uiProps = [NSMutableDictionary new];
NSMutableDictionary *nativeProps = [NSMutableDictionary new];
NSMutableDictionary *jsProps = [NSMutableDictionary new];
void (^addBlock)(NSString *key, id obj, BOOL * stop) = ^(NSString *key, id obj, BOOL * stop){
if ([self.nodesManager.uiProps containsObject:key]) {
uiProps[key] = obj;
} else if ([self.nodesManager.nativeProps containsObject:key]) {
nativeProps[key] = obj;
} else {
jsProps[key] = obj;
}
};
for (NSString *prop in _propsConfig) {
REANode *propNode = [self.nodesManager findNodeByID:_propsConfig[prop]];
if ([propNode isKindOfClass:[REAStyleNode class]]) {
[[propNode value] enumerateKeysAndObjectsUsingBlock:addBlock];
} else {
addBlock(prop, [propNode value], nil);
}
}
if (_connectedViewTag != nil) {
if (uiProps.count > 0) {
[self.nodesManager.uiManager
synchronouslyUpdateViewOnUIThread:_connectedViewTag
viewName:_connectedViewName
props:uiProps];
}
if (nativeProps.count > 0) {
[self.nodesManager enqueueUpdateViewOnNativeThread:_connectedViewTag viewName:_connectedViewName nativeProps:nativeProps];
}
if (jsProps.count > 0) {
[self.nodesManager.reanimatedModule
sendEventWithName:@"onReanimatedPropsChange"
body:@{@"viewTag": _connectedViewTag, @"props": jsProps }];
}
}
return @(0);
}
- (void)update
{
// Since we are updating nodes after detaching them from views there is a time where it's
// possible that the view was disconnected and still receive an update, this is normal and we can
// simply skip that update.
if (!_connectedViewTag) {
return;
}
// triger for side effect
[self value];
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REASetNode : REANode
@end

View File

@ -0,0 +1,32 @@
#import "REASetNode.h"
#import "REAUtils.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#import "REAValueNode.h"
#import "REANodesManager.h"
@implementation REASetNode {
NSNumber *_whatNodeID;
NSNumber *_valueNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_whatNodeID = [RCTConvert NSNumber:config[@"what"]];
REA_LOG_ERROR_IF_NIL(_whatNodeID, @"Reanimated: First argument passed to set node is either of wrong type or is missing.");
_valueNodeID = [RCTConvert NSNumber:config[@"value"]];
REA_LOG_ERROR_IF_NIL(_valueNodeID, @"Reanimated: Second argument passed to set node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
NSNumber *newValue = [[self.nodesManager findNodeByID:_valueNodeID] value];
REAValueNode *what = (REAValueNode *)[self.nodesManager findNodeByID:_whatNodeID];
[what setValue:newValue];
return newValue;
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REAStyleNode : REANode
@end

View File

@ -0,0 +1,30 @@
#import "REAStyleNode.h"
#import "REANodesManager.h"
@implementation REAStyleNode
{
NSMutableDictionary<NSString *, REANodeID> *_styleConfig;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config;
{
if ((self = [super initWithID:nodeID config:config])) {
_styleConfig = config[@"style"];
}
return self;
}
- (id)evaluate
{
NSMutableDictionary *styles = [NSMutableDictionary new];
for (NSString *prop in _styleConfig) {
REANode *propNode = [self.nodesManager findNodeByID:_styleConfig[prop]];
styles[prop] = [propNode value];
}
return styles;
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REATransformNode : REANode
@end

View File

@ -0,0 +1,38 @@
#import "REATransformNode.h"
#import <React/RCTConvert.h>
#import "REANodesManager.h"
@implementation REATransformNode
{
NSArray<id> *_transformConfigs;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_transformConfigs = config[@"transform"];
}
return self;
}
- (id)evaluate
{
NSMutableArray<NSDictionary *> *transform = [NSMutableArray arrayWithCapacity:_transformConfigs.count];
for (NSDictionary *transformConfig in _transformConfigs) {
NSString *property = transformConfig[@"property"];
REANodeID nodeID = [RCTConvert NSNumber:transformConfig[@"nodeID"]];
NSNumber *value;
if (nodeID) {
REANode *node = [self.nodesManager findNodeByID:nodeID];
value = [node value];
} else {
value = transformConfig[@"value"];
}
[transform addObject:@{property: value}];
}
return transform;
}
@end

View File

@ -0,0 +1,11 @@
#import <UIKit/UIKit.h>
#import "REANode.h"
@class REAValueNode;
@interface REAValueNode : REANode
- (void)setValue:(NSNumber *)value;
@end

View File

@ -0,0 +1,28 @@
#import "REAValueNode.h"
@implementation REAValueNode {
NSNumber *_value;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config
{
if (self = [super initWithID:nodeID config:config]) {
_value = config[@"value"];
}
return self;
}
- (void)setValue:(NSNumber *)value
{
_value = value;
[self forceUpdateMemoizedValue:value];
}
- (id)evaluate
{
return _value;
}
@end