Fabric: Application layer of events infrastructure

Summary: This implements `EventHandlers` abstract class (aka "Events Guy") which encapsulates `eventDispatcher` and `instanceHandle` (and ownership of future `eventTarget`), all of this as part of existing {ShadowNode + Props + LayoutMetrics + LocalData + Descriptor + (and now) EventHandlers} infra. (We don't plan to add anything else to this model. Ever.)

Reviewed By: fkgozali

Differential Revision: D8053351

fbshipit-source-id: 1dd9ccbcbe5a2eb284b59ea351dc8beca645e8bf
This commit is contained in:
Valentin Shergin 2018-05-22 15:48:19 -07:00 committed by Facebook Github Bot
parent d94a9e2640
commit 2a3025da97
22 changed files with 350 additions and 77 deletions

View File

@ -22,6 +22,7 @@ rn_xplat_cxx_library(
exported_headers = subdir_glob(
[
("", "*.h"),
("events", "*.h"),
("primitives", "*.h"),
("componentdescriptor", "*.h"),
("layout", "*.h"),

View File

@ -47,7 +47,7 @@ public:
virtual SharedShadowNode createShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedEventHandlers &eventHandlers,
const SharedProps &props
) const = 0;
@ -57,6 +57,7 @@ public:
virtual SharedShadowNode cloneShadowNode(
const SharedShadowNode &shadowNode,
const SharedProps &props = nullptr,
const SharedEventHandlers &eventHandlers = nullptr,
const SharedShadowNodeSharedList &children = nullptr
) const = 0;
@ -78,6 +79,14 @@ public:
const SharedProps &props,
const RawProps &rawProps
) const = 0;
/*
* Creates a new `EventHandlers` object compatible with particular type of
* shadow nodes.
*/
virtual SharedEventHandlers createEventHandlers(
const InstanceHandle &instanceHandle
) const = 0;
};
} // namespace react

View File

@ -29,8 +29,13 @@ class ConcreteComponentDescriptor: public ComponentDescriptor {
using SharedShadowNodeT = std::shared_ptr<const ShadowNodeT>;
using ConcreteProps = typename ShadowNodeT::ConcreteProps;
using SharedConcreteProps = typename ShadowNodeT::SharedConcreteProps;
using ConcreteEventHandlers = typename ShadowNodeT::ConcreteEventHandlers;
using SharedConcreteEventHandlers = typename ShadowNodeT::SharedConcreteEventHandlers;
public:
ConcreteComponentDescriptor(SharedEventDispatcher eventDispatcher):
eventDispatcher_(eventDispatcher) {}
ComponentHandle getComponentHandle() const override {
return typeid(ShadowNodeT).hash_code();
}
@ -43,8 +48,8 @@ public:
return std::make_shared<ShadowNodeT>(
0,
0,
nullptr,
std::make_shared<const ConcreteProps>(),
nullptr,
ShadowNode::emptySharedShadowNodeSharedList(),
nullptr
)->ShadowNodeT::getComponentName();
@ -53,17 +58,21 @@ public:
SharedShadowNode createShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedEventHandlers &eventHandlers,
const SharedProps &props
) const override {
UnsharedShadowNode shadowNode = std::make_shared<ShadowNodeT>(
assert(std::dynamic_pointer_cast<const ConcreteProps>(props));
assert(std::dynamic_pointer_cast<const ConcreteEventHandlers>(eventHandlers));
auto &&shadowNode = std::make_shared<ShadowNodeT>(
tag,
rootTag,
instanceHandle,
std::static_pointer_cast<const ConcreteProps>(props),
std::static_pointer_cast<const ConcreteEventHandlers>(eventHandlers),
ShadowNode::emptySharedShadowNodeSharedList(),
getCloneFunction()
);
adopt(shadowNode);
return shadowNode;
}
@ -71,10 +80,18 @@ public:
SharedShadowNode cloneShadowNode(
const SharedShadowNode &sourceShadowNode,
const SharedProps &props = nullptr,
const SharedEventHandlers &eventHandlers = nullptr,
const SharedShadowNodeSharedList &children = nullptr
) const override {
assert(std::dynamic_pointer_cast<const ShadowNodeT>(sourceShadowNode));
UnsharedShadowNode shadowNode = std::make_shared<ShadowNodeT>(std::static_pointer_cast<const ShadowNodeT>(sourceShadowNode), std::static_pointer_cast<const ConcreteProps>(props), children);
auto &&shadowNode = std::make_shared<ShadowNodeT>(
std::static_pointer_cast<const ShadowNodeT>(sourceShadowNode),
std::static_pointer_cast<const ConcreteProps>(props),
std::static_pointer_cast<const ConcreteEventHandlers>(eventHandlers),
children
);
adopt(shadowNode);
return shadowNode;
}
@ -95,6 +112,12 @@ public:
return ShadowNodeT::Props(rawProps, props);
};
virtual SharedEventHandlers createEventHandlers(
const InstanceHandle &instanceHandle
) const override {
return std::make_shared<ConcreteEventHandlers>(instanceHandle, eventDispatcher_);
}
protected:
virtual void adopt(UnsharedShadowNode shadowNode) const {
@ -103,13 +126,15 @@ protected:
private:
mutable SharedEventDispatcher eventDispatcher_ {nullptr};
mutable ShadowNodeCloneFunction cloneFunction_;
ShadowNodeCloneFunction getCloneFunction() const {
if (!cloneFunction_) {
cloneFunction_ = [this](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) {
cloneFunction_ = [this](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedEventHandlers &eventHandlers, const SharedShadowNodeSharedList &children) {
assert(std::dynamic_pointer_cast<const ShadowNodeT>(shadowNode));
return this->cloneShadowNode(shadowNode, props, children);
return this->cloneShadowNode(shadowNode, props, eventHandlers, children);
};
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <memory>
#include <fabric/core/ReactPrimitives.h>
#include <fabric/core/EventPrimitives.h>
#include <folly/dynamic.h>
namespace facebook {
namespace react {
class EventDispatcher;
using SharedEventDispatcher = std::shared_ptr<const EventDispatcher>;
/*
* Abstract class that represent event-delivery infrastructure.
* Particular `EventHandlers` clases use an object of this class to invoke
* events.
*/
class EventDispatcher {
public:
/*
* Dispatches "raw" event using some event-delivery infrastructure.
*/
virtual void dispatchEvent(
const InstanceHandle &instanceHandle,
const std::string &name,
const folly::dynamic &payload,
const EventPriority &priority
) const = 0;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "EventHandlers.h"
#include <folly/dynamic.h>
namespace facebook {
namespace react {
EventHandlers::EventHandlers(InstanceHandle instanceHandle, SharedEventDispatcher eventDispatcher):
instanceHandle_(instanceHandle),
eventDispatcher_(eventDispatcher) {}
void EventHandlers::dispatchEvent(
const std::string &name,
const folly::dynamic &payload,
const EventPriority &priority
) const {
auto &&eventDispatcher = eventDispatcher_.lock();
if (!eventDispatcher) {
return;
}
// TODO(T29610783): Reconsider using dynamic dispatch here.
eventDispatcher->dispatchEvent(instanceHandle_, name, payload, priority);
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <memory>
#include <folly/dynamic.h>
#include <fabric/core/EventDispatcher.h>
#include <fabric/core/EventPrimitives.h>
#include <fabric/core/ReactPrimitives.h>
namespace facebook {
namespace react {
class EventHandlers;
using SharedEventHandlers = std::shared_ptr<const EventHandlers>;
/*
* Base class for all particular typed event handlers.
* Stores `InstanceHandle` identifying a particular component and the pointer
* to `EventDispatcher` which is responsible for delivering the event.
*
* TODO: Reconsider naming of all event-related things.
*/
class EventHandlers {
public:
EventHandlers(InstanceHandle instanceHandle, SharedEventDispatcher eventDispatcher);
virtual ~EventHandlers() = default;
protected:
/*
* Initates an event delivery process.
* Is used by particular subclasses only.
*/
void dispatchEvent(
const std::string &name,
const folly::dynamic &payload = {},
const EventPriority &priority = EventPriority::AsynchronousBatched
) const;
private:
InstanceHandle instanceHandle_;
std::weak_ptr<const EventDispatcher> eventDispatcher_;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
namespace facebook {
namespace react {
enum class EventPriority {
SynchronousUnbatched,
SynchronousBatched,
AsynchronousUnbatched,
AsynchronousBatched,
Sync = SynchronousUnbatched,
Work = SynchronousBatched,
Interactive = AsynchronousUnbatched,
Deferred = AsynchronousBatched,
};
} // namespace react
} // namespace facebook

View File

@ -19,13 +19,15 @@ namespace react {
* `ConcreteShadowNode` is a default implementation of `ShadowNode` interface
* with many handy features.
*/
template <typename PropsT>
template <typename PropsT, typename EventHandlersT = EventHandlers>
class ConcreteShadowNode: public ShadowNode {
static_assert(std::is_base_of<Props, PropsT>::value, "PropsT must be a descendant of Props");
public:
using ConcreteProps = PropsT;
using SharedConcreteProps = std::shared_ptr<const PropsT>;
using ConcreteEventHandlers = EventHandlersT;
using SharedConcreteEventHandlers = std::shared_ptr<const EventHandlersT>;
using SharedConcreteShadowNode = std::shared_ptr<const ConcreteShadowNode>;
static SharedConcreteProps Props(const RawProps &rawProps, const SharedProps &baseProps = nullptr) {
@ -40,16 +42,16 @@ public:
ConcreteShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedConcreteProps &props,
const SharedConcreteEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children,
const ShadowNodeCloneFunction &cloneFunction
):
ShadowNode(
tag,
rootTag,
instanceHandle,
(SharedProps)props,
eventHandlers,
children,
cloneFunction
) {};
@ -57,11 +59,13 @@ public:
ConcreteShadowNode(
const SharedConcreteShadowNode &shadowNode,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children
):
ShadowNode(
shadowNode,
(SharedProps)props,
eventHandlers,
children
) {}

View File

@ -23,15 +23,15 @@ SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
ShadowNode::ShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children,
const ShadowNodeCloneFunction &cloneFunction
):
tag_(tag),
rootTag_(rootTag),
instanceHandle_(instanceHandle),
props_(props),
eventHandlers_(eventHandlers),
children_(std::make_shared<SharedShadowNodeList>(*children)),
cloneFunction_(cloneFunction),
revision_(1) {}
@ -39,12 +39,13 @@ ShadowNode::ShadowNode(
ShadowNode::ShadowNode(
const SharedShadowNode &shadowNode,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children
):
tag_(shadowNode->tag_),
rootTag_(shadowNode->rootTag_),
instanceHandle_(shadowNode->instanceHandle_),
props_(props ? props : shadowNode->props_),
eventHandlers_(eventHandlers ? eventHandlers : shadowNode->eventHandlers_),
children_(std::make_shared<SharedShadowNodeList>(*(children ? children : shadowNode->children_))),
sourceNode_(shadowNode),
localData_(shadowNode->localData_),
@ -56,7 +57,7 @@ SharedShadowNode ShadowNode::clone(
const SharedShadowNodeSharedList &children
) const {
assert(cloneFunction_);
return cloneFunction_(shared_from_this(), props_, children_);
return cloneFunction_(shared_from_this(), props_, eventHandlers_, children_);
}
#pragma mark - Getters
@ -69,6 +70,10 @@ SharedProps ShadowNode::getProps() const {
return props_;
}
SharedEventHandlers ShadowNode::getEventHandlers() const {
return eventHandlers_;
}
Tag ShadowNode::getTag() const {
return tag_;
}
@ -77,10 +82,6 @@ Tag ShadowNode::getRootTag() const {
return rootTag_;
}
InstanceHandle ShadowNode::getInstanceHandle() const {
return instanceHandle_;
}
SharedShadowNode ShadowNode::getSourceNode() const {
return sourceNode_.lock();
}
@ -146,6 +147,7 @@ bool ShadowNode::operator==(const ShadowNode& rhs) const {
tag_ == rhs.tag_ &&
rootTag_ == rhs.rootTag_ &&
props_ == rhs.props_ &&
eventHandlers_ == rhs.eventHandlers_ &&
localData_ == rhs.localData_;
}
@ -181,10 +183,6 @@ SharedDebugStringConvertibleList ShadowNode::getDebugProps() const {
list.push_back(std::make_shared<DebugStringConvertibleItem>("tag", std::to_string(tag_)));
if (instanceHandle_) {
list.push_back(std::make_shared<DebugStringConvertibleItem>("handle", std::to_string((size_t)instanceHandle_)));
}
SharedShadowNode sourceNode = getSourceNode();
if (sourceNode) {
list.push_back(std::make_shared<DebugStringConvertibleItem>(

View File

@ -11,6 +11,7 @@
#include <memory>
#include <vector>
#include <fabric/core/EventHandlers.h>
#include <fabric/core/LocalData.h>
#include <fabric/core/Props.h>
#include <fabric/core/ReactPrimitives.h>
@ -29,7 +30,12 @@ using SharedShadowNodeSharedList = std::shared_ptr<const SharedShadowNodeList>;
using SharedShadowNodeUnsharedList = std::shared_ptr<SharedShadowNodeList>;
using WeakShadowNode = std::weak_ptr<const ShadowNode>;
using ShadowNodeCloneFunction = std::function<SharedShadowNode(SharedShadowNode shadowNode, SharedProps props, SharedShadowNodeSharedList children)>;
using ShadowNodeCloneFunction = std::function<SharedShadowNode(
const SharedShadowNode &shadowNode,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children
)>;
class ShadowNode:
public virtual Sealable,
@ -43,8 +49,8 @@ public:
ShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children,
const ShadowNodeCloneFunction &cloneFunction
);
@ -52,6 +58,7 @@ public:
ShadowNode(
const SharedShadowNode &shadowNode,
const SharedProps &props,
const SharedEventHandlers &eventHandlers,
const SharedShadowNodeSharedList &children
);
@ -70,9 +77,9 @@ public:
SharedShadowNodeSharedList getChildren() const;
SharedProps getProps() const;
SharedEventHandlers getEventHandlers() const;
Tag getTag() const;
Tag getRootTag() const;
InstanceHandle getInstanceHandle() const;
/*
* Returns the node which was used as a prototype in clone constructor.
@ -135,8 +142,8 @@ public:
protected:
Tag tag_;
Tag rootTag_;
InstanceHandle instanceHandle_;
SharedProps props_;
SharedEventHandlers eventHandlers_;
SharedShadowNodeSharedList children_;
WeakShadowNode sourceNode_;
SharedLocalData localData_;

View File

@ -12,7 +12,7 @@
using namespace facebook::react;
TEST(ComponentDescriptorTest, createShadowNode) {
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>();
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
ASSERT_EQ(descriptor->getComponentHandle(), typeid(TestShadowNode).hash_code());
ASSERT_STREQ(descriptor->getComponentName().c_str(), "Test");
@ -20,7 +20,7 @@ TEST(ComponentDescriptorTest, createShadowNode) {
RawProps raw;
raw["nativeID"] = "abc";
SharedProps props = descriptor->cloneProps(nullptr, raw);
SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, props);
SharedShadowNode node = descriptor->createShadowNode(9, 1, nullptr, props);
ASSERT_EQ(node->getComponentHandle(), typeid(TestShadowNode).hash_code());
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
@ -30,12 +30,12 @@ TEST(ComponentDescriptorTest, createShadowNode) {
}
TEST(ComponentDescriptorTest, cloneShadowNode) {
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>();
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
RawProps raw;
raw["nativeID"] = "abc";
SharedProps props = descriptor->cloneProps(nullptr, raw);
SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, props);
SharedShadowNode node = descriptor->createShadowNode(9, 1, nullptr, props);
SharedShadowNode cloned = descriptor->cloneShadowNode(node);
ASSERT_EQ(cloned->getComponentHandle(), typeid(TestShadowNode).hash_code());
@ -46,14 +46,14 @@ TEST(ComponentDescriptorTest, cloneShadowNode) {
}
TEST(ComponentDescriptorTest, appendChild) {
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>();
SharedComponentDescriptor descriptor = std::make_shared<TestComponentDescriptor>(nullptr);
RawProps raw;
raw["nativeID"] = "abc";
SharedProps props = descriptor->cloneProps(nullptr, raw);
SharedShadowNode node1 = descriptor->createShadowNode(1, 1, (void *)NULL, props);
SharedShadowNode node2 = descriptor->createShadowNode(2, 1, (void *)NULL, props);
SharedShadowNode node3 = descriptor->createShadowNode(3, 1, (void *)NULL, props);
SharedShadowNode node1 = descriptor->createShadowNode(1, 1, nullptr, props);
SharedShadowNode node2 = descriptor->createShadowNode(2, 1, nullptr, props);
SharedShadowNode node3 = descriptor->createShadowNode(3, 1, nullptr, props);
descriptor->appendChild(node1, node2);
descriptor->appendChild(node1, node3);

View File

@ -28,13 +28,13 @@ TEST(ShadowNodeTest, handleProps) {
}
TEST(ShadowNodeTest, handleShadowNodeCreation) {
auto node = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, std::make_shared<const TestProps>(), ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node = std::make_shared<TestShadowNode>(9, 1, std::make_shared<const TestProps>(), nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
ASSERT_FALSE(node->getSealed());
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1);
ASSERT_EQ(node->getInstanceHandle(), (void *)NULL);
ASSERT_EQ(node->getEventHandlers(), nullptr);
TestShadowNode *nodePtr = node.get();
ASSERT_EQ(node->getComponentHandle(), typeid(*nodePtr).hash_code());
ASSERT_EQ(node->getSourceNode(), nullptr);
@ -48,21 +48,21 @@ TEST(ShadowNodeTest, handleShadowNodeCreation) {
}
TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) {
auto node = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, std::make_shared<const TestProps>(), ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node2 = std::make_shared<TestShadowNode>(node, nullptr, nullptr);
auto node = std::make_shared<TestShadowNode>(9, 1, std::make_shared<const TestProps>(), nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node2 = std::make_shared<TestShadowNode>(node, nullptr, nullptr, nullptr);
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1);
ASSERT_EQ(node->getInstanceHandle(), (void *)NULL);
ASSERT_EQ(node->getEventHandlers(), nullptr);
ASSERT_EQ(node2->getSourceNode(), node);
}
TEST(ShadowNodeTest, handleShadowNodeMutation) {
auto props = std::make_shared<const TestProps>();
auto node1 = std::make_shared<TestShadowNode>(1, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node2 = std::make_shared<TestShadowNode>(2, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node3 = std::make_shared<TestShadowNode>(3, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node1 = std::make_shared<TestShadowNode>(1, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node2 = std::make_shared<TestShadowNode>(2, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto node3 = std::make_shared<TestShadowNode>(3, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
node1->appendChild(node2);
node1->appendChild(node3);
@ -71,7 +71,7 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) {
ASSERT_EQ(node1Children->at(0), node2);
ASSERT_EQ(node1Children->at(1), node3);
auto node4 = std::make_shared<TestShadowNode>(node2, nullptr, nullptr);
auto node4 = std::make_shared<TestShadowNode>(node2, nullptr, nullptr, nullptr);
node1->replaceChild(node2, node4);
node1Children = node1->getChildren();
ASSERT_EQ(node1Children->size(), 2);
@ -87,16 +87,16 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) {
// No more mutation after sealing.
EXPECT_THROW(node4->clearSourceNode(), std::runtime_error);
auto node5 = std::make_shared<TestShadowNode>(node4, nullptr, nullptr);
auto node5 = std::make_shared<TestShadowNode>(node4, nullptr, nullptr, nullptr);
node5->clearSourceNode();
ASSERT_EQ(node5->getSourceNode(), nullptr);
}
TEST(ShadowNodeTest, handleSourceNode) {
auto nodeFirstGeneration = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, std::make_shared<const TestProps>(), ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto nodeSecondGeneration = std::make_shared<TestShadowNode>(nodeFirstGeneration, nullptr, nullptr);
auto nodeThirdGeneration = std::make_shared<TestShadowNode>(nodeSecondGeneration, nullptr, nullptr);
auto nodeForthGeneration = std::make_shared<TestShadowNode>(nodeThirdGeneration, nullptr, nullptr);
auto nodeFirstGeneration = std::make_shared<TestShadowNode>(9, 1, std::make_shared<const TestProps>(), nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto nodeSecondGeneration = std::make_shared<TestShadowNode>(nodeFirstGeneration, nullptr, nullptr, nullptr);
auto nodeThirdGeneration = std::make_shared<TestShadowNode>(nodeSecondGeneration, nullptr, nullptr, nullptr);
auto nodeForthGeneration = std::make_shared<TestShadowNode>(nodeThirdGeneration, nullptr, nullptr, nullptr);
// Ensure established shource nodes structure.
ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeThirdGeneration);
@ -117,7 +117,7 @@ TEST(ShadowNodeTest, handleSourceNode) {
}
TEST(ShadowNodeTest, handleCloneFunction) {
auto firstNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, std::make_shared<const TestProps>(), ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto firstNode = std::make_shared<TestShadowNode>(9, 1, std::make_shared<const TestProps>(), nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
// The shadow node is not clonable if `cloneFunction` is not provided,
ASSERT_DEATH_IF_SUPPORTED(firstNode->clone(), "cloneFunction_");
@ -125,13 +125,14 @@ TEST(ShadowNodeTest, handleCloneFunction) {
auto secondNode = std::make_shared<TestShadowNode>(
9,
1,
(void *)NULL,
std::make_shared<const TestProps>(),
nullptr,
ShadowNode::emptySharedShadowNodeSharedList(),
[](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) {
[](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedEventHandlers &eventHandlers, const SharedShadowNodeSharedList &children) {
return std::make_shared<const TestShadowNode>(
std::static_pointer_cast<const TestShadowNode>(shadowNode),
props,
nullptr,
children
);
}
@ -161,9 +162,9 @@ TEST(ShadowNodeTest, handleLocalData) {
auto localDataOver9000 = std::make_shared<TestLocalData>();
localDataOver9000->setNumber(9001);
auto props = std::make_shared<const TestProps>();
auto firstNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto secondNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto thirdNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL, props, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto firstNode = std::make_shared<TestShadowNode>(9, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto secondNode = std::make_shared<TestShadowNode>(9, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
auto thirdNode = std::make_shared<TestShadowNode>(9, 1, props, nullptr, ShadowNode::emptySharedShadowNodeSharedList(), nullptr);
firstNode->setLocalData(localData42);
secondNode->setLocalData(localData42);

View File

@ -57,6 +57,8 @@ public:
class TestComponentDescriptor: public ConcreteComponentDescriptor<TestShadowNode> {
public:
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
// TODO (shergin): Why does this gets repeated here and the shadow node class?
ComponentName getComponentName() const override {
return "Test";

View File

@ -14,7 +14,7 @@ namespace react {
/**
* This is a sample implementation. Each app should provide its own.
*/
SharedComponentDescriptorRegistry ComponentDescriptorFactory::buildRegistry() {
SharedComponentDescriptorRegistry ComponentDescriptorFactory::buildRegistry(const SharedEventDispatcher &eventDispatcher) {
auto registry = std::make_shared<ComponentDescriptorRegistry>();
return registry;
}

View File

@ -10,6 +10,7 @@
#include <memory>
#include <fabric/core/ComponentDescriptor.h>
#include <fabric/core/EventDispatcher.h>
#include "ComponentDescriptorRegistry.h"
@ -24,7 +25,7 @@ namespace react {
class ComponentDescriptorFactory {
public:
static SharedComponentDescriptorRegistry buildRegistry();
static SharedComponentDescriptorRegistry buildRegistry(const SharedEventDispatcher &eventDispatcher);
};
} // namespace react

View File

@ -91,7 +91,7 @@ UIManagerDelegate *FabricUIManager::getDelegate() {
return delegate_;
}
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) {
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag" << rootTag << ", props: " << props << ")";
ComponentName componentName = componentNameByReactViewName(viewName);
@ -102,7 +102,7 @@ SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int
componentDescriptor->createShadowNode(
tag,
rootTag,
instanceHandle,
componentDescriptor->createEventHandlers(instanceHandle),
componentDescriptor->cloneProps(nullptr, rawProps)
);
@ -115,28 +115,32 @@ SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int
return shadowNode;
}
SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode, void *instanceHandle) {
SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
// TODO: Retain new instanceHandle
SharedShadowNode clonedShadowNode =
componentDescriptor->cloneShadowNode(shadowNode);
componentDescriptor->cloneShadowNode(
shadowNode,
nullptr,
componentDescriptor->createEventHandlers(instanceHandle),
nullptr
);
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false});
return clonedShadowNode;
}
SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode, void *instanceHandle) {
SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")";
// Assuming semantic: Cloning with same props but empty children.
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
// TODO: Retain new instanceHandle
SharedShadowNode clonedShadowNode =
componentDescriptor->cloneShadowNode(
shadowNode,
nullptr,
componentDescriptor->createEventHandlers(instanceHandle),
ShadowNode::emptySharedShadowNodeSharedList()
);
@ -144,17 +148,17 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNod
return clonedShadowNode;
}
SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props, void *instanceHandle) {
SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
// Assuming semantic: Cloning with same children and specified props.
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
RawProps rawProps = rawPropsFromDynamic(props);
// TODO: Retain new instanceHandle
SharedShadowNode clonedShadowNode =
componentDescriptor->cloneShadowNode(
shadowNode,
componentDescriptor->cloneProps(shadowNode->getProps(), rawProps),
componentDescriptor->createEventHandlers(instanceHandle),
nullptr
);
@ -162,17 +166,17 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &
return clonedShadowNode;
}
SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props, void *instanceHandle) {
SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")";
// Assuming semantic: Cloning with empty children and specified props.
const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode];
RawProps rawProps = rawPropsFromDynamic(props);
// TODO: Retain new instanceHandle
SharedShadowNode clonedShadowNode =
componentDescriptor->cloneShadowNode(
shadowNode,
componentDescriptor->cloneProps(shadowNode->getProps(), rawProps),
componentDescriptor->createEventHandlers(instanceHandle),
ShadowNode::emptySharedShadowNodeSharedList()
);

View File

@ -35,11 +35,11 @@ public:
#pragma mark - JavaScript/React-facing Interface
SharedShadowNode createNode(Tag reactTag, std::string viewName, Tag rootTag, folly::dynamic props, void *instanceHandle);
SharedShadowNode cloneNode(const SharedShadowNode &node, void *instanceHandle);
SharedShadowNode cloneNodeWithNewChildren(const SharedShadowNode &node, void *instanceHandle);
SharedShadowNode cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props, void *instanceHandle);
SharedShadowNode cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps, void *instanceHandle);
SharedShadowNode createNode(Tag reactTag, std::string viewName, Tag rootTag, folly::dynamic props, InstanceHandle instanceHandle);
SharedShadowNode cloneNode(const SharedShadowNode &node, InstanceHandle instanceHandle);
SharedShadowNode cloneNodeWithNewChildren(const SharedShadowNode &node, InstanceHandle instanceHandle);
SharedShadowNode cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props, InstanceHandle instanceHandle);
SharedShadowNode cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps, InstanceHandle instanceHandle);
void appendChild(const SharedShadowNode &parentNode, const SharedShadowNode &childNode);
SharedShadowNodeUnsharedList createChildSet(Tag rootTag);
void appendChildToSet(const SharedShadowNodeUnsharedList &childSet, const SharedShadowNode &childNode);

View File

@ -20,7 +20,8 @@ namespace facebook {
namespace react {
Scheduler::Scheduler() {
auto componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry();
eventDispatcher_ = std::make_shared<SchedulerEventDispatcher>();
auto componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher_);
uiManager_ = std::make_shared<FabricUIManager>(componentDescriptorRegistry);
uiManager_->setDelegate(this);
}

View File

@ -7,6 +7,7 @@
#include <fabric/core/ComponentDescriptor.h>
#include <fabric/core/LayoutConstraints.h>
#include <fabric/uimanager/SchedulerDelegate.h>
#include <fabric/uimanager/SchedulerEventDispatcher.h>
#include <fabric/uimanager/UIManagerDelegate.h>
#include <fabric/uimanager/ShadowTree.h>
#include <fabric/uimanager/ShadowTreeDelegate.h>
@ -69,6 +70,7 @@ private:
SchedulerDelegate *delegate_;
std::shared_ptr<FabricUIManager> uiManager_;
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
std::shared_ptr<SchedulerEventDispatcher> eventDispatcher_;
};
} // namespace react

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SchedulerEventDispatcher.h"
namespace facebook {
namespace react {
void SchedulerEventDispatcher::dispatchEvent(
const InstanceHandle &instanceHandle,
const std::string &name,
const folly::dynamic &payload,
const EventPriority &priority
) const {
// Some future magic here.
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <fabric/core/EventDispatcher.h>
#include <fabric/core/EventPrimitives.h>
#include <folly/dynamic.h>
namespace facebook {
namespace react {
/*
* Concrete EventDispatcher.
*/
class SchedulerEventDispatcher final:
public EventDispatcher {
public:
void dispatchEvent(
const InstanceHandle &instanceHandle,
const std::string &name,
const folly::dynamic &payload,
const EventPriority &priority
) const override;
};
} // namespace react
} // namespace facebook

View File

@ -15,11 +15,12 @@ namespace react {
ShadowTree::ShadowTree(Tag rootTag):
rootTag_(rootTag) {
auto &&noopEventHandlers = std::make_shared<const ViewEventHandlers>(nullptr, nullptr);
rootShadowNode_ = std::make_shared<RootShadowNode>(
rootTag,
rootTag,
nullptr,
RootShadowNode::defaultSharedProps(),
noopEventHandlers,
ShadowNode::emptySharedShadowNodeSharedList(),
nullptr
);
@ -47,14 +48,14 @@ void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, co
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto oldRootShadowNode = rootShadowNode_;
auto &&props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
auto newRootShadowNode = std::make_shared<RootShadowNode>(oldRootShadowNode, props, nullptr);
auto newRootShadowNode = std::make_shared<RootShadowNode>(oldRootShadowNode, props, nullptr, nullptr);
return newRootShadowNode;
}
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
auto oldRootShadowNode = rootShadowNode_;
auto newRootShadowNode =
std::make_shared<RootShadowNode>(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes));
std::make_shared<RootShadowNode>(oldRootShadowNode, nullptr, nullptr, SharedShadowNodeSharedList(rootChildNodes));
complete(newRootShadowNode);
}