Fabric: Unification of registration process of `ComponentView`s and `ComponentDescriptor`s
Summary: Registries, providers, providers of registries, registres of providers. All that can be really confusing, but that represents best the constraints and desires that we have: * We need to be able to register components on-the-fly (so we need a mechanism that will propagate changes); * We don't want to register ComponentDescriptors separately from ComponentView classes; * C++ not always gives us abstractions that we want (e.g. pointers to constructors). After the change, we can remove the whole Buck target that has a bunch of handwritten boilerplate code. There is a still room for polish and removing some concepts, types or classes but this diff is already huge. Reviewed By: JoshuaGross Differential Revision: D14983906 fbshipit-source-id: ce536ebea0c905059c7a4d644dc25233e2809761
This commit is contained in:
Родитель
00eab3d6fb
Коммит
832164169d
|
@ -9,6 +9,8 @@
|
|||
|
||||
#import <React/RCTComponentViewProtocol.h>
|
||||
|
||||
#import <react/uimanager/ComponentDescriptorRegistry.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
|
@ -27,12 +29,24 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass;
|
||||
|
||||
/**
|
||||
* Unregisters a component view class in the factory.
|
||||
*/
|
||||
- (void)unregisterComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass;
|
||||
|
||||
/**
|
||||
* Creates a component view with given component handle.
|
||||
*/
|
||||
- (UIView<RCTComponentViewProtocol> *)createComponentViewWithComponentHandle:
|
||||
(facebook::react::ComponentHandle)componentHandle;
|
||||
|
||||
/**
|
||||
* Creates *managed* `ComponentDescriptorRegistry`. After creation, the object continues to store a weak pointer to the
|
||||
* registry and update it accordingly to the changes in the object.
|
||||
*/
|
||||
- (facebook::react::ComponentDescriptorRegistry::Shared)createComponentDescriptorRegistryWithParameters:
|
||||
(facebook::react::ComponentDescriptorParameters)parameters;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
#import "RCTComponentViewFactory.h"
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <better/map.h>
|
||||
#import <better/mutex.h>
|
||||
|
||||
#import <react/core/ReactPrimitives.h>
|
||||
#import <react/uimanager/ComponentDescriptorProviderRegistry.h>
|
||||
|
||||
#import "RCTActivityIndicatorViewComponentView.h"
|
||||
#import "RCTImageComponentView.h"
|
||||
|
@ -23,13 +27,13 @@
|
|||
using namespace facebook::react;
|
||||
|
||||
@implementation RCTComponentViewFactory {
|
||||
std::unordered_map<ComponentHandle, Class<RCTComponentViewProtocol>> _registry;
|
||||
better::map<ComponentHandle, Class<RCTComponentViewProtocol>> _componentViewClasses;
|
||||
ComponentDescriptorProviderRegistry _providerRegistry;
|
||||
better::shared_mutex _mutex;
|
||||
}
|
||||
|
||||
+ (RCTComponentViewFactory *)standardComponentViewFactory
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
|
||||
RCTComponentViewFactory *componentViewFactory = [[RCTComponentViewFactory alloc] init];
|
||||
|
||||
[componentViewFactory registerComponentViewClass:[RCTViewComponentView class]];
|
||||
|
@ -47,20 +51,36 @@ using namespace facebook::react;
|
|||
|
||||
- (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
std::unique_lock<better::shared_mutex> lock(_mutex);
|
||||
|
||||
auto componentHandle = [componentViewClass componentDescriptorProvider].handle;
|
||||
_registry[componentHandle] = componentViewClass;
|
||||
auto componentDescriptorProvider = [componentViewClass componentDescriptorProvider];
|
||||
_componentViewClasses[componentDescriptorProvider.handle] = componentViewClass;
|
||||
_providerRegistry.add(componentDescriptorProvider);
|
||||
|
||||
auto supplementalComponentDescriptorProviders = [componentViewClass supplementalComponentDescriptorProviders];
|
||||
for (const auto &provider : supplementalComponentDescriptorProviders) {
|
||||
_providerRegistry.add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unregisterComponentViewClass:(Class<RCTComponentViewProtocol>)componentViewClass
|
||||
{
|
||||
std::unique_lock<better::shared_mutex> lock(_mutex);
|
||||
|
||||
auto componentDescriptorProvider = [componentViewClass componentDescriptorProvider];
|
||||
_componentViewClasses.erase(componentDescriptorProvider.handle);
|
||||
_providerRegistry.remove(componentDescriptorProvider);
|
||||
}
|
||||
|
||||
- (UIView<RCTComponentViewProtocol> *)createComponentViewWithComponentHandle:
|
||||
(facebook::react::ComponentHandle)componentHandle
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
std::shared_lock<better::shared_mutex> lock(_mutex);
|
||||
|
||||
auto iterator = _registry.find(componentHandle);
|
||||
auto iterator = _componentViewClasses.find(componentHandle);
|
||||
RCTAssert(
|
||||
iterator != _registry.end(),
|
||||
iterator != _componentViewClasses.end(),
|
||||
@"ComponentView with componentHandle `%lli` (`%s`) not found.",
|
||||
componentHandle,
|
||||
(char *)componentHandle);
|
||||
|
@ -68,4 +88,12 @@ using namespace facebook::react;
|
|||
return [[componentViewClass alloc] init];
|
||||
}
|
||||
|
||||
- (facebook::react::ComponentDescriptorRegistry::Shared)createComponentDescriptorRegistryWithParameters:
|
||||
(facebook::react::ComponentDescriptorParameters)parameters
|
||||
{
|
||||
std::shared_lock<better::shared_mutex> lock(_mutex);
|
||||
|
||||
return _providerRegistry.createComponentDescriptorRegistry(parameters);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#import <react/core/LayoutConstraints.h>
|
||||
#import <react/core/LayoutContext.h>
|
||||
#import <react/mounting/ShadowViewMutation.h>
|
||||
#import <react/uimanager/ComponentDescriptorFactory.h>
|
||||
#import <react/utils/ContextContainer.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -38,7 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (atomic, weak, nullable) id<RCTSchedulerDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithContextContainer:(facebook::react::ContextContainer::Shared)contextContatiner;
|
||||
- (instancetype)initWithContextContainer:(facebook::react::ContextContainer::Shared)contextContatiner
|
||||
componentRegistryFactory:(facebook::react::ComponentRegistryFactory)componentRegistryFactory;
|
||||
|
||||
- (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId
|
||||
moduleName:(NSString *)moduleName
|
||||
|
|
|
@ -48,10 +48,11 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
|
|||
}
|
||||
|
||||
- (instancetype)initWithContextContainer:(ContextContainer::Shared)contextContainer
|
||||
componentRegistryFactory:(ComponentRegistryFactory)componentRegistryFactory
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_delegateProxy = std::make_shared<SchedulerDelegateProxy>((__bridge void *)self);
|
||||
_scheduler = std::make_shared<Scheduler>(contextContainer, getDefaultComponentRegistryFactory());
|
||||
_scheduler = std::make_shared<Scheduler>(contextContainer, componentRegistryFactory);
|
||||
_scheduler->setDelegate(_delegateProxy.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTBridge+Private.h>
|
||||
#import <React/RCTComponentViewFactory.h>
|
||||
#import <React/RCTComponentViewRegistry.h>
|
||||
#import <React/RCTFabricSurface.h>
|
||||
#import <React/RCTFollyConvert.h>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#import <react/core/LayoutConstraints.h>
|
||||
#import <react/core/LayoutContext.h>
|
||||
#import <react/imagemanager/ImageManager.h>
|
||||
#import <react/uimanager/ComponentDescriptorFactory.h>
|
||||
#import <react/utils/ContextContainer.h>
|
||||
|
||||
#import "MainRunLoopEventBeat.h"
|
||||
|
@ -193,7 +195,15 @@ using namespace facebook::react;
|
|||
return _scheduler;
|
||||
}
|
||||
|
||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:self.contextContainer];
|
||||
auto componentRegistryFactory = [factory = RNWrapManagedObject(self.componentViewFactory)](
|
||||
EventDispatcher::Shared const &eventDispatcher,
|
||||
ContextContainer::Shared const &contextContainer) {
|
||||
return [(RCTComponentViewFactory *)RNUnwrapManagedObject(factory)
|
||||
createComponentDescriptorRegistryWithParameters:{eventDispatcher, contextContainer}];
|
||||
};
|
||||
|
||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:self.contextContainer
|
||||
componentRegistryFactory:componentRegistryFactory];
|
||||
_scheduler.delegate = self;
|
||||
|
||||
return _scheduler;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace react {
|
|||
|
||||
class ComponentDescriptor;
|
||||
|
||||
using SharedComponentDescriptor = std::shared_ptr<ComponentDescriptor>;
|
||||
using SharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>;
|
||||
|
||||
/*
|
||||
* Abstract class defining an interface of `ComponentDescriptor`.
|
||||
|
|
|
@ -14,6 +14,16 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Represents a collection of arguments that sufficient to construct a
|
||||
* `ComponentDescriptor`.
|
||||
*/
|
||||
class ComponentDescriptorParameters {
|
||||
public:
|
||||
EventDispatcher::Shared eventDispatcher;
|
||||
ContextContainer::Shared contextContainer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Callable signature that represents the signature of `ComponentDescriptor`
|
||||
* constructor. The callable returns a unique pointer conveniently represents an
|
||||
|
@ -32,6 +42,7 @@ using ComponentDescriptorConstructor = ComponentDescriptor::Unique(
|
|||
class ComponentDescriptorProvider final {
|
||||
public:
|
||||
ComponentHandle handle;
|
||||
ComponentName name;
|
||||
ComponentDescriptorConstructor *constructor;
|
||||
};
|
||||
|
||||
|
@ -62,6 +73,7 @@ ComponentDescriptorProvider concreteComponentDescriptorProvider() {
|
|||
"ComponentDescriptorT must be a descendant of ComponentDescriptor");
|
||||
|
||||
return {ComponentDescriptorT::ConcreteShadowNode::Handle(),
|
||||
ComponentDescriptorT::ConcreteShadowNode::Name(),
|
||||
&concreteComponentDescriptorConstructor<ComponentDescriptorT>};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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 "ComponentDescriptorProviderRegistry.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
void ComponentDescriptorProviderRegistry::add(
|
||||
ComponentDescriptorProvider provider) const {
|
||||
std::unique_lock<better::shared_mutex> lock(mutex_);
|
||||
componentDescriptorProviders_.insert({provider.handle, provider});
|
||||
|
||||
for (auto const &weakRegistry : componentDescriptorRegistries_) {
|
||||
auto registry = weakRegistry.lock();
|
||||
if (!registry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
registry->add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentDescriptorProviderRegistry::remove(
|
||||
ComponentDescriptorProvider provider) const {
|
||||
std::unique_lock<better::shared_mutex> lock(mutex_);
|
||||
componentDescriptorProviders_.erase(provider.handle);
|
||||
|
||||
for (auto const &weakRegistry : componentDescriptorRegistries_) {
|
||||
auto registry = weakRegistry.lock();
|
||||
if (!registry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
registry->remove(provider);
|
||||
}
|
||||
}
|
||||
|
||||
ComponentDescriptorRegistry::Shared
|
||||
ComponentDescriptorProviderRegistry::createComponentDescriptorRegistry(
|
||||
ComponentDescriptorParameters const ¶meters) const {
|
||||
std::shared_lock<better::shared_mutex> lock(mutex_);
|
||||
|
||||
auto registry =
|
||||
std::make_shared<ComponentDescriptorRegistry const>(parameters);
|
||||
|
||||
for (auto const &pair : componentDescriptorProviders_) {
|
||||
registry->add(pair.second);
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* 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 <better/mutex.h>
|
||||
|
||||
#include <react/core/ComponentDescriptor.h>
|
||||
#include <react/uimanager/ComponentDescriptorProvider.h>
|
||||
#include <react/uimanager/ComponentDescriptorRegistry.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Registry of `ComponentDescriptorProvider`s (and managed
|
||||
* `ComponentDescriptorRegistry`s). The class maintains a list of
|
||||
* `ComponentDescriptorRegistry`s (retaining pointers weakly) and update them
|
||||
* accordingly to changes in the provider registry.
|
||||
*/
|
||||
class ComponentDescriptorProviderRegistry final {
|
||||
public:
|
||||
/*
|
||||
* Adds (or removes) a `ComponentDescriptorProvider`s and update the managed
|
||||
* `ComponentDescriptorRegistry`s accordingly.
|
||||
*/
|
||||
void add(ComponentDescriptorProvider provider) const;
|
||||
void remove(ComponentDescriptorProvider provider) const;
|
||||
|
||||
/*
|
||||
* Creates managed `ComponentDescriptorRegistry` based on a stored list of
|
||||
* `ComponentDescriptorProvider`s and given `ComponentDescriptorParameters`.
|
||||
*/
|
||||
ComponentDescriptorRegistry::Shared createComponentDescriptorRegistry(
|
||||
ComponentDescriptorParameters const ¶meters) const;
|
||||
|
||||
private:
|
||||
mutable better::shared_mutex mutex_;
|
||||
mutable std::vector<std::weak_ptr<ComponentDescriptorRegistry const>>
|
||||
componentDescriptorRegistries_;
|
||||
mutable better::map<ComponentHandle, ComponentDescriptorProvider const>
|
||||
componentDescriptorProviders_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -11,8 +11,47 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
ComponentDescriptorRegistry::ComponentDescriptorRegistry(
|
||||
ComponentDescriptorParameters const ¶meters)
|
||||
: parameters_(parameters) {}
|
||||
|
||||
void ComponentDescriptorRegistry::add(
|
||||
ComponentDescriptorProvider componentDescriptorProvider) const {
|
||||
std::unique_lock<better::shared_mutex> lock(mutex_);
|
||||
|
||||
auto componentDescriptor = componentDescriptorProvider.constructor(
|
||||
parameters_.eventDispatcher, parameters_.contextContainer);
|
||||
assert(
|
||||
componentDescriptor->getComponentHandle() ==
|
||||
componentDescriptorProvider.handle);
|
||||
assert(
|
||||
componentDescriptor->getComponentName() ==
|
||||
componentDescriptorProvider.name);
|
||||
|
||||
auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
|
||||
std::move(componentDescriptor));
|
||||
_registryByHandle[componentDescriptorProvider.handle] =
|
||||
sharedComponentDescriptor;
|
||||
_registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;
|
||||
}
|
||||
|
||||
void ComponentDescriptorRegistry::remove(
|
||||
ComponentDescriptorProvider componentDescriptorProvider) const {
|
||||
std::unique_lock<better::shared_mutex> lock(mutex_);
|
||||
|
||||
assert(
|
||||
_registryByHandle.find(componentDescriptorProvider.handle) !=
|
||||
_registryByHandle.end());
|
||||
assert(
|
||||
_registryByName.find(componentDescriptorProvider.name) !=
|
||||
_registryByName.end());
|
||||
|
||||
_registryByHandle.erase(componentDescriptorProvider.handle);
|
||||
_registryByName.erase(componentDescriptorProvider.name);
|
||||
}
|
||||
|
||||
void ComponentDescriptorRegistry::registerComponentDescriptor(
|
||||
SharedComponentDescriptor componentDescriptor) {
|
||||
SharedComponentDescriptor componentDescriptor) const {
|
||||
ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
|
||||
_registryByHandle[componentHandle] = componentDescriptor;
|
||||
|
||||
|
@ -72,6 +111,8 @@ static ComponentName componentNameByReactViewName(ComponentName viewName) {
|
|||
|
||||
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
||||
ComponentName const &componentName) const {
|
||||
std::shared_lock<better::shared_mutex> lock(mutex_);
|
||||
|
||||
auto unifiedComponentName = componentNameByReactViewName(componentName);
|
||||
|
||||
auto it = _registryByName.find(unifiedComponentName);
|
||||
|
@ -88,6 +129,8 @@ ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|||
|
||||
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
||||
ComponentHandle componentHandle) const {
|
||||
std::shared_lock<better::shared_mutex> lock(mutex_);
|
||||
|
||||
return *_registryByHandle.at(componentHandle);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
#include <memory>
|
||||
|
||||
#include <better/map.h>
|
||||
#include <better/mutex.h>
|
||||
|
||||
#include <react/core/ComponentDescriptor.h>
|
||||
#include <react/uimanager/ComponentDescriptorProvider.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -25,8 +28,22 @@ class ComponentDescriptorRegistry {
|
|||
public:
|
||||
using Shared = std::shared_ptr<const ComponentDescriptorRegistry>;
|
||||
|
||||
/*
|
||||
* Deprecated. Use custom constructor instead.
|
||||
*/
|
||||
ComponentDescriptorRegistry() = default;
|
||||
|
||||
/*
|
||||
* Creates an object with stored `ComponentDescriptorParameters` which will
|
||||
* be used later to create `ComponentDescriptor`s.
|
||||
*/
|
||||
ComponentDescriptorRegistry(ComponentDescriptorParameters const ¶meters);
|
||||
|
||||
/*
|
||||
* Deprecated. Use `add` instead.
|
||||
*/
|
||||
void registerComponentDescriptor(
|
||||
SharedComponentDescriptor componentDescriptor);
|
||||
SharedComponentDescriptor componentDescriptor) const;
|
||||
|
||||
ComponentDescriptor const &at(ComponentName const &componentName) const;
|
||||
ComponentDescriptor const &at(ComponentHandle componentHandle) const;
|
||||
|
@ -42,9 +59,23 @@ class ComponentDescriptorRegistry {
|
|||
ComponentDescriptor::Shared getFallbackComponentDescriptor() const;
|
||||
|
||||
private:
|
||||
better::map<ComponentHandle, SharedComponentDescriptor> _registryByHandle;
|
||||
better::map<ComponentName, SharedComponentDescriptor> _registryByName;
|
||||
friend class ComponentDescriptorProviderRegistry;
|
||||
|
||||
/*
|
||||
* Adds (or removes) a `ComponentDescriptor ` created using given
|
||||
* `ComponentDescriptorProvider` and stored `ComponentDescriptorParameters`.
|
||||
* To be used by `ComponentDescriptorProviderRegistry` only.
|
||||
* Thread safe.
|
||||
*/
|
||||
void add(ComponentDescriptorProvider componentDescriptorProvider) const;
|
||||
void remove(ComponentDescriptorProvider componentDescriptorProvider) const;
|
||||
|
||||
mutable better::shared_mutex mutex_;
|
||||
mutable better::map<ComponentHandle, SharedComponentDescriptor>
|
||||
_registryByHandle;
|
||||
mutable better::map<ComponentName, SharedComponentDescriptor> _registryByName;
|
||||
ComponentDescriptor::Shared _fallbackComponentDescriptor;
|
||||
ComponentDescriptorParameters parameters_{};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
|
Загрузка…
Ссылка в новой задаче