Skip to content

Commit

Permalink
Fabric: Unification of registration process of ComponentViews and `…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
shergin authored and facebook-github-bot committed Apr 18, 2019
1 parent 00eab3d commit 8321641
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 16 deletions.
14 changes: 14 additions & 0 deletions React/Fabric/Mounting/RCTComponentViewFactory.h
Expand Up @@ -9,6 +9,8 @@

#import <React/RCTComponentViewProtocol.h>

#import <react/uimanager/ComponentDescriptorRegistry.h>

NS_ASSUME_NONNULL_BEGIN

/**
Expand All @@ -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
44 changes: 36 additions & 8 deletions React/Fabric/Mounting/RCTComponentViewFactory.mm
Expand Up @@ -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"
Expand All @@ -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]];
Expand All @@ -47,25 +51,49 @@ + (RCTComponentViewFactory *)standardComponentViewFactory

- (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);
Class componentViewClass = iterator->second;
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
4 changes: 3 additions & 1 deletion React/Fabric/RCTScheduler.h
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion React/Fabric/RCTScheduler.mm
Expand Up @@ -48,10 +48,11 @@ @implementation RCTScheduler {
}

- (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());
}

Expand Down
12 changes: 11 additions & 1 deletion React/Fabric/RCTSurfacePresenter.mm
Expand Up @@ -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>
Expand All @@ -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"
Expand Down Expand Up @@ -193,7 +195,15 @@ - (RCTScheduler *)_scheduler
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;
Expand Down
Expand Up @@ -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`.
Expand Down
12 changes: 12 additions & 0 deletions ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h
Expand Up @@ -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
Expand All @@ -32,6 +42,7 @@ using ComponentDescriptorConstructor = ComponentDescriptor::Unique(
class ComponentDescriptorProvider final {
public:
ComponentHandle handle;
ComponentName name;
ComponentDescriptorConstructor *constructor;
};

Expand Down Expand Up @@ -62,6 +73,7 @@ ComponentDescriptorProvider concreteComponentDescriptorProvider() {
"ComponentDescriptorT must be a descendant of ComponentDescriptor");

return {ComponentDescriptorT::ConcreteShadowNode::Handle(),
ComponentDescriptorT::ConcreteShadowNode::Name(),
&concreteComponentDescriptorConstructor<ComponentDescriptorT>};
}

Expand Down
@@ -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 &parameters) 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
50 changes: 50 additions & 0 deletions ReactCommon/fabric/uimanager/ComponentDescriptorProviderRegistry.h
@@ -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 &parameters) 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

0 comments on commit 8321641

Please sign in to comment.