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,39 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <CoreFoundation/CFRunLoop.h>
#include <CoreFoundation/CoreFoundation.h>
#include <react/core/EventBeat.h>
#include <react/utils/RuntimeExecutor.h>
namespace facebook {
namespace react {
/*
* Event beat associated with main run loop cycle.
* The callback is always called on the main thread.
*/
class MainRunLoopEventBeat final : public EventBeat {
public:
MainRunLoopEventBeat(
EventBeat::SharedOwnerBox const &ownerBox,
RuntimeExecutor runtimeExecutor);
~MainRunLoopEventBeat();
void induce() const override;
private:
void lockExecutorAndBeat() const;
const RuntimeExecutor runtimeExecutor_;
CFRunLoopObserverRef mainRunLoopObserver_;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "MainRunLoopEventBeat.h"
#import <React/RCTUtils.h>
#import <mutex>
namespace facebook {
namespace react {
MainRunLoopEventBeat::MainRunLoopEventBeat(EventBeat::SharedOwnerBox const &ownerBox, RuntimeExecutor runtimeExecutor)
: EventBeat(ownerBox), runtimeExecutor_(std::move(runtimeExecutor))
{
mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler(
NULL /* allocator */,
kCFRunLoopBeforeWaiting /* activities */,
true /* repeats */,
0 /* order */,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
if (!this->isRequested_) {
return;
}
this->lockExecutorAndBeat();
});
assert(mainRunLoopObserver_);
CFRunLoopAddObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
}
MainRunLoopEventBeat::~MainRunLoopEventBeat()
{
CFRunLoopRemoveObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
CFRelease(mainRunLoopObserver_);
}
void MainRunLoopEventBeat::induce() const
{
if (!this->isRequested_) {
return;
}
RCTExecuteOnMainQueue(^{
this->lockExecutorAndBeat();
});
}
void MainRunLoopEventBeat::lockExecutorAndBeat() const
{
auto owner = ownerBox_->owner.lock();
if (!owner) {
return;
}
executeSynchronouslyOnSameThread_CAN_DEADLOCK(runtimeExecutor_, [this](jsi::Runtime &runtime) { beat(runtime); });
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
* General purpose implementation of Delegate Splitter (or Multicast) pattern which allows subscribing multiple
* `receiving` objects to single `sending` object (which normally does not support that feature by itself).
*
* In the case where only one receiving object is registered, using Splitter has zero performance overhead because the
* receiver is being subscribed directly. In the case where more than one receiving objects are registered, using
* Splitter introduces some performance overhead.
*/
@interface RCTGenericDelegateSplitter<DelegateT> : NSObject
@property (nonatomic, copy, nullable) void (^delegateUpdateBlock)(DelegateT _Nullable delegate);
/*
* Creates an object with a given block that will be used to connect a `sending` object with a given `receiving` object.
* The class calls the block every time after each delegate adding or removing procedure, and it calls it twice: the
* first time with `nil` and the second time with actual delegate. This is required to establish a proper connection
* between sending and receiving objects (to reset caches storing information about supported (or not) optional
* methods).
*/
- (instancetype)initWithDelegateUpdateBlock:(void (^)(DelegateT _Nullable delegate))block;
/*
* Adds and removes a delegate.
* The delegates will be called in order of registration.
* If a delegate returns a value, the value from the last call will be passed to the `sending` object.
*/
- (void)addDelegate:(DelegateT)delegate;
- (void)removeDelegate:(DelegateT)delegate;
- (void)removeAllDelegates;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTGenericDelegateSplitter.h"
@implementation RCTGenericDelegateSplitter {
NSHashTable *_delegates;
}
#pragma mark - Public
- (instancetype)initWithDelegateUpdateBlock:(void (^)(id _Nullable delegate))block
{
if (self = [super init]) {
_delegateUpdateBlock = block;
_delegates = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void)addDelegate:(id)delegate
{
[_delegates addObject:delegate];
[self _updateDelegate];
}
- (void)removeDelegate:(id)delegate
{
[_delegates removeObject:delegate];
[self _updateDelegate];
}
- (void)removeAllDelegates
{
[_delegates removeAllObjects];
[self _updateDelegate];
}
#pragma mark - Private
- (void)_updateDelegate
{
_delegateUpdateBlock(nil);
if (_delegates.count == 0) {
return;
}
_delegateUpdateBlock(_delegates.count == 1 ? [_delegates allObjects].firstObject : self);
}
#pragma mark - Fast Forwarding
- (BOOL)respondsToSelector:(SEL)selector
{
for (id delegate in _delegates) {
if ([delegate respondsToSelector:selector]) {
return YES;
}
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
for (id delegate in _delegates) {
if ([delegate respondsToSelector:selector]) {
return [delegate methodSignatureForSelector:selector];
}
}
return nil;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSMutableArray *targets = [[NSMutableArray alloc] initWithCapacity:_delegates.count];
for (id delegate in _delegates) {
if ([delegate respondsToSelector:[invocation selector]]) {
[targets addObject:delegate];
}
}
for (id target in targets) {
[invocation invokeWithTarget:target];
}
}
@end

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <CoreFoundation/CFRunLoop.h>
#include <CoreFoundation/CoreFoundation.h>
#include <react/core/EventBeat.h>
#include <react/utils/RuntimeExecutor.h>
namespace facebook {
namespace react {
/*
* Event beat associated with JavaScript runtime.
* The beat is called on `RuntimeExecutor`'s thread induced by the main thread
* event loop.
*/
class RuntimeEventBeat : public EventBeat {
public:
RuntimeEventBeat(
EventBeat::SharedOwnerBox const &ownerBox,
RuntimeExecutor runtimeExecutor);
~RuntimeEventBeat();
void induce() const override;
private:
const RuntimeExecutor runtimeExecutor_;
CFRunLoopObserverRef mainRunLoopObserver_;
mutable std::atomic<bool> isBusy_{false};
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "RuntimeEventBeat.h"
namespace facebook {
namespace react {
RuntimeEventBeat::RuntimeEventBeat(EventBeat::SharedOwnerBox const &ownerBox, RuntimeExecutor runtimeExecutor)
: EventBeat(ownerBox), runtimeExecutor_(std::move(runtimeExecutor))
{
mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler(
NULL /* allocator */,
kCFRunLoopBeforeWaiting /* activities */,
true /* repeats */,
0 /* order */,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
// Note: We only `induce` beat here; actual beat will be performed on
// a different thread.
this->induce();
});
assert(mainRunLoopObserver_);
CFRunLoopAddObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
}
RuntimeEventBeat::~RuntimeEventBeat()
{
CFRunLoopRemoveObserver(CFRunLoopGetMain(), mainRunLoopObserver_, kCFRunLoopCommonModes);
CFRelease(mainRunLoopObserver_);
}
void RuntimeEventBeat::induce() const
{
if (!isRequested_ || isBusy_) {
return;
}
isBusy_ = true;
runtimeExecutor_([this, ownerBox = ownerBox_](jsi::Runtime &runtime) mutable {
auto owner = ownerBox->owner.lock();
if (!owner) {
return;
}
this->beat(runtime);
isBusy_ = false;
});
}
} // namespace react
} // namespace facebook