From c6234558458fc3c8eb7bf742782189e8df8b8b90 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 18 Mar 2018 19:04:10 -0700 Subject: [PATCH] Abstract classes for ShadowNode and Props Summary: Foundation clases for Fabric designed to be "const-first". Reviewed By: fkgozali Differential Revision: D7230672 fbshipit-source-id: 433acd35a7958d5d577358b0a306923f970e573f --- ReactCommon/fabric/FabricUIManager.cpp | 29 ++-- ReactCommon/fabric/FabricUIManager.h | 25 ++-- ReactCommon/fabric/ShadowNode.cpp | 20 --- ReactCommon/fabric/ShadowNode.h | 27 ---- ReactCommon/fabric/core/BUCK | 1 + .../fabric/core/primitives/ReactPrimitives.h | 55 +++++++ ReactCommon/fabric/core/shadownode/Props.cpp | 29 ++++ ReactCommon/fabric/core/shadownode/Props.h | 38 +++++ .../fabric/core/shadownode/ShadowNode.cpp | 134 ++++++++++++++++++ .../fabric/core/shadownode/ShadowNode.h | 80 +++++++++++ 10 files changed, 362 insertions(+), 76 deletions(-) delete mode 100644 ReactCommon/fabric/ShadowNode.cpp delete mode 100644 ReactCommon/fabric/ShadowNode.h create mode 100644 ReactCommon/fabric/core/primitives/ReactPrimitives.h create mode 100644 ReactCommon/fabric/core/shadownode/Props.cpp create mode 100644 ReactCommon/fabric/core/shadownode/Props.h create mode 100644 ReactCommon/fabric/core/shadownode/ShadowNode.cpp create mode 100644 ReactCommon/fabric/core/shadownode/ShadowNode.h diff --git a/ReactCommon/fabric/FabricUIManager.cpp b/ReactCommon/fabric/FabricUIManager.cpp index 54262fc9edb..9b6ec3216e6 100644 --- a/ReactCommon/fabric/FabricUIManager.cpp +++ b/ReactCommon/fabric/FabricUIManager.cpp @@ -8,7 +8,6 @@ #include "FabricUIManager.h" #include "IFabricPlatformUIOperationManager.h" -#include "ShadowNode.h" namespace facebook { namespace react { @@ -16,38 +15,38 @@ namespace react { FabricUIManager::FabricUIManager(const std::shared_ptr &platformUIOperationManager) : platformUIOperationManager_(platformUIOperationManager) {}; -ShadowNodeRef FabricUIManager::createNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) { +SharedShadowNode FabricUIManager::createNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) { platformUIOperationManager_->performUIOperation(); - return std::make_shared(reactTag, viewName, rootTag, props, instanceHandle); -} - -ShadowNodeRef FabricUIManager::cloneNode(const ShadowNodeRef &node) { return nullptr; } -ShadowNodeRef FabricUIManager::cloneNodeWithNewChildren(const ShadowNodeRef &node) { +SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &node) { return nullptr; } -ShadowNodeRef FabricUIManager::cloneNodeWithNewProps(const ShadowNodeRef &node, folly::dynamic props) { +SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &node) { return nullptr; } -ShadowNodeRef FabricUIManager::cloneNodeWithNewChildrenAndProps(const ShadowNodeRef &node, folly::dynamic newProps) { +SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props) { return nullptr; } -void FabricUIManager::appendChild(const ShadowNodeRef &parentNode, const ShadowNodeRef &childNode) { -} - -ShadowNodeSetRef FabricUIManager::createChildSet(int rootTag) { +SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps) { return nullptr; } -void FabricUIManager::appendChildToSet(const ShadowNodeSetRef &childSet, const ShadowNodeRef &childNode) { +void FabricUIManager::appendChild(const SharedShadowNode &parentNode, const SharedShadowNode &childNode) { } -void FabricUIManager::completeRoot(int rootTag, const ShadowNodeSetRef &childSet) { +SharedShadowNodeUnsharedList FabricUIManager::createChildSet(int rootTag) { + return nullptr; +} + +void FabricUIManager::appendChildToSet(const SharedShadowNodeUnsharedList &childSet, const SharedShadowNode &childNode) { +} + +void FabricUIManager::completeRoot(int rootTag, const SharedShadowNodeUnsharedList &childSet) { } } // namespace react diff --git a/ReactCommon/fabric/FabricUIManager.h b/ReactCommon/fabric/FabricUIManager.h index 06ee2a94f70..4857a4291d7 100644 --- a/ReactCommon/fabric/FabricUIManager.h +++ b/ReactCommon/fabric/FabricUIManager.h @@ -11,29 +11,26 @@ #include #include +#include + namespace facebook { namespace react { -class ShadowNode; class IFabricPlatformUIOperationManager; -typedef std::shared_ptr ShadowNodeRef; -typedef folly::fbvector ShadowNodeSet; -typedef std::shared_ptr ShadowNodeSetRef; - class FabricUIManager { public: FabricUIManager(const std::shared_ptr &platformUIOperationManager); - ShadowNodeRef createNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle); - ShadowNodeRef cloneNode(const ShadowNodeRef &node); - ShadowNodeRef cloneNodeWithNewChildren(const ShadowNodeRef &node); - ShadowNodeRef cloneNodeWithNewProps(const ShadowNodeRef &node, folly::dynamic props); - ShadowNodeRef cloneNodeWithNewChildrenAndProps(const ShadowNodeRef &node, folly::dynamic newProps); - void appendChild(const ShadowNodeRef &parentNode, const ShadowNodeRef &childNode); - ShadowNodeSetRef createChildSet(int rootTag); - void appendChildToSet(const ShadowNodeSetRef &childSet, const ShadowNodeRef &childNode); - void completeRoot(int rootTag, const ShadowNodeSetRef &childSet); + SharedShadowNode createNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle); + SharedShadowNode cloneNode(const SharedShadowNode &node); + SharedShadowNode cloneNodeWithNewChildren(const SharedShadowNode &node); + SharedShadowNode cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props); + SharedShadowNode cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps); + void appendChild(const SharedShadowNode &parentNode, const SharedShadowNode &childNode); + SharedShadowNodeUnsharedList createChildSet(int rootTag); + void appendChildToSet(const SharedShadowNodeUnsharedList &childSet, const SharedShadowNode &childNode); + void completeRoot(int rootTag, const SharedShadowNodeUnsharedList &childSet); private: std::shared_ptr platformUIOperationManager_; diff --git a/ReactCommon/fabric/ShadowNode.cpp b/ReactCommon/fabric/ShadowNode.cpp deleted file mode 100644 index 9f675572bc8..00000000000 --- a/ReactCommon/fabric/ShadowNode.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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 "ShadowNode.h" - -namespace facebook { -namespace react { - -ShadowNode::ShadowNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) : - reactTag_(reactTag), - viewName_(viewName), - rootTag_(rootTag), - props_(props), - instanceHandle_(instanceHandle) {} - -}} diff --git a/ReactCommon/fabric/ShadowNode.h b/ReactCommon/fabric/ShadowNode.h deleted file mode 100644 index 257b7c19e94..00000000000 --- a/ReactCommon/fabric/ShadowNode.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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 -#include - -namespace facebook { -namespace react { - -class ShadowNode { -public: - int reactTag_; - std::string viewName_; - int rootTag_; - folly::dynamic props_; - void *instanceHandle_; - - ShadowNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle); -}; - -}} diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 4001090955b..ec92dc42c2c 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -23,6 +23,7 @@ rn_xplat_cxx_library( exported_headers = subdir_glob( [ ("primitives", "*.h"), + ("shadownode", "*.h"), ], prefix = "fabric/core", ), diff --git a/ReactCommon/fabric/core/primitives/ReactPrimitives.h b/ReactCommon/fabric/core/primitives/ReactPrimitives.h new file mode 100644 index 00000000000..0b5004ab2ca --- /dev/null +++ b/ReactCommon/fabric/core/primitives/ReactPrimitives.h @@ -0,0 +1,55 @@ +/** + * 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 +#include + +#include + +namespace facebook { +namespace react { + +/* + * `Tag` and `InstanceHandle` are used to address React Native components. + */ +using Tag = int32_t; +using InstanceHandle = void *; + +/* + * `RawProps` represents untyped map with props comes from JavaScript side. + */ +// TODO(T26954420): Use iterator as underlying type for RawProps. +using RawProps = std::map; +using SharedRawProps = std::shared_ptr; + +/* + * Components event handlers. + * Something which usually called from JavaScript side. + */ +using BubblingEventHandler = void (*)(void); +using SharedBubblingEventHandler = std::shared_ptr; +using DirectEventHandler = void (*)(void); +using SharedDirectEventHandler = std::shared_ptr; + +/* + * Universal component handle which allows to refer to `ComponentDescriptor`s + * in maps efficiently. + * Practically, it's something that concrete ShadowNode and concrete + * ComponentDescriptor have in common. + */ +using ComponentHandle = size_t; + +/* + * String identifier for components used for addressing them from + * JavaScript side. + */ +using ComponentName = std::string; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/Props.cpp b/ReactCommon/fabric/core/shadownode/Props.cpp new file mode 100644 index 00000000000..fb527d62be9 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/Props.cpp @@ -0,0 +1,29 @@ +/** + * 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 "Props.h" + +#include + +namespace facebook { +namespace react { + +void Props::apply(const RawProps &rawProps) { + ensureUnsealed(); + + for (auto const &pair : rawProps) { + auto const &name = pair.first; + auto const &value = pair.second; + + if (name == "nativeID") { + nativeId_ = value.asString(); + } + } +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/Props.h b/ReactCommon/fabric/core/shadownode/Props.h new file mode 100644 index 00000000000..da9f4f3b6f1 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/Props.h @@ -0,0 +1,38 @@ +/** + * 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 + +#include +#include +#include + +namespace facebook { +namespace react { + +class Props; + +using SharedProps = std::shared_ptr; + +/* + * Represents the most generic props object. + */ +class Props: + public virtual Sealable, + public virtual DebugStringConvertible { + +public: + virtual void apply(const RawProps &rawProps); + +private: + std::string nativeId_ {""}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp new file mode 100644 index 00000000000..1f2777429d1 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -0,0 +1,134 @@ +/** + * 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 "ShadowNode.h" + +#include +#include + +namespace facebook { +namespace react { + +SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() { + static const auto emptySharedShadowNodeSharedList = std::make_shared(); + return emptySharedShadowNodeSharedList; +} + +#pragma mark - Constructors + +ShadowNode::ShadowNode( + Tag tag, + InstanceHandle instanceHandle, + SharedProps props, + SharedShadowNodeSharedList children +): + tag_(tag), + instanceHandle_(instanceHandle), + props_(props), + children_(children) {} + +ShadowNode::ShadowNode( + SharedShadowNode shadowNode, + SharedProps props, + SharedShadowNodeSharedList children +): + tag_(shadowNode->tag_), + instanceHandle_(shadowNode->instanceHandle_), + props_(props ? props : shadowNode->props_), + children_(children ? children : shadowNode->children_) {} + +#pragma mark - Getters + +SharedShadowNodeSharedList ShadowNode::getChildren() const { + return children_; +} + +SharedProps ShadowNode::getProps() const { + return props_; +} + +Tag ShadowNode::getTag() const { + return tag_; +} + +#pragma mark - Mutating Methods + +void ShadowNode::sealRecursive() const { + if (getSealed()) { + return; + } + + seal(); + + props_->seal(); + + for (auto child : *children_) { + child->sealRecursive(); + } +} + +void ShadowNode::appendChild(const SharedShadowNode &child) { + ensureUnsealed(); + + // We cannot mutate `children_` in place here because it is a *shared* + // data structure which means other `ShadowNodes` might refer to its old value. + // So, we have to clone this and only then mutate. + auto nonConstChildrenCopy = SharedShadowNodeList(*children_); + nonConstChildrenCopy.push_back(child); + children_ = std::make_shared(nonConstChildrenCopy); +} + +void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild) { + ensureUnsealed(); + + // We cannot mutate `children_` in place here because it is a *shared* + // data structure which means other `ShadowNodes` might refer to its old value. + // So, we have to clone this and only then mutate. + auto nonConstChildrenCopy = SharedShadowNodeList(*children_); + std::replace(nonConstChildrenCopy.begin(), nonConstChildrenCopy.end(), oldChild, newChild); + children_ = std::make_shared(nonConstChildrenCopy); +} + +#pragma mark - DebugStringConvertible + +std::string ShadowNode::getDebugName() const { + return getComponentName(); +} + +std::string ShadowNode::getDebugValue() const { + return getSealed() ? "sealed" : ""; +} + +SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const { + SharedDebugStringConvertibleList debugChildren = {}; + + for (auto child : *children_) { + auto debugChild = std::dynamic_pointer_cast(child); + if (debugChild) { + debugChildren.push_back(debugChild); + } + } + + return debugChildren; +} + +SharedDebugStringConvertibleList ShadowNode::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + + list.push_back(std::make_shared("tag", std::to_string(tag_))); + + if (instanceHandle_) { + list.push_back(std::make_shared("handle", std::to_string((size_t)instanceHandle_))); + } + + SharedDebugStringConvertibleList propsList = props_->getDebugProps(); + std::move(propsList.begin(), propsList.end(), std::back_inserter(list)); + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h new file mode 100644 index 00000000000..f341d6f12e6 --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -0,0 +1,80 @@ +/** + * 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 +#include + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class ShadowNode; + +using SharedShadowNode = std::shared_ptr; +using SharedShadowNodeList = std::vector>; +using SharedShadowNodeSharedList = std::shared_ptr; +using SharedShadowNodeUnsharedList = std::shared_ptr; + +class ShadowNode: + public virtual Sealable, + public virtual DebugStringConvertible { +public: + static SharedShadowNodeSharedList emptySharedShadowNodeSharedList(); + +#pragma mark - Constructors + + ShadowNode( + Tag tag, + InstanceHandle instanceHandle, + SharedProps props = SharedProps(), + SharedShadowNodeSharedList children = SharedShadowNodeSharedList() + ); + + ShadowNode( + SharedShadowNode shadowNode, + SharedProps props = nullptr, + SharedShadowNodeSharedList children = nullptr + ); + +#pragma mark - Getters + + virtual ComponentHandle getComponentHandle() const = 0; + virtual ComponentName getComponentName() const = 0; + + SharedShadowNodeSharedList getChildren() const; + SharedProps getProps() const; + Tag getTag() const; + +#pragma mark - Mutating Methods + + void sealRecursive() const; + + void appendChild(const SharedShadowNode &child); + void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild); + +#pragma mark - DebugStringConvertible + + std::string getDebugName() const override; + std::string getDebugValue() const override; + SharedDebugStringConvertibleList getDebugChildren() const override; + SharedDebugStringConvertibleList getDebugProps() const override; + +protected: + Tag tag_; + InstanceHandle instanceHandle_; + SharedProps props_; + SharedShadowNodeSharedList children_; +}; + +} // namespace react +} // namespace facebook