diff --git a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h index 68f603840ef..bd58941c459 100644 --- a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h @@ -124,5 +124,32 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode { YGMeasureMode heightMode); }; +template <> +inline YogaLayoutableShadowNode const & +traitCast(ShadowNode const &shadowNode) { + bool castable = + shadowNode.getTraits().check(ShadowNodeTraits::Trait::YogaLayoutableKind); + assert( + castable == + (dynamic_cast(&shadowNode) != nullptr)); + assert(castable); + (void)castable; + return static_cast(shadowNode); +} + +template <> +inline YogaLayoutableShadowNode const * +traitCast(ShadowNode const *shadowNode) { + bool castable = shadowNode->getTraits().check( + ShadowNodeTraits::Trait::YogaLayoutableKind); + assert( + castable == + (dynamic_cast(shadowNode) != nullptr)); + if (!castable) { + return nullptr; + } + return static_cast(shadowNode); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h index ca946be4589..ec6e8e485e6 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h @@ -160,5 +160,32 @@ class LayoutableShadowNode : public ShadowNode { LayoutMetrics layoutMetrics_; }; +template <> +inline LayoutableShadowNode const &traitCast( + ShadowNode const &shadowNode) { + bool castable = + shadowNode.getTraits().check(ShadowNodeTraits::Trait::LayoutableKind); + assert( + castable == + (dynamic_cast(&shadowNode) != nullptr)); + assert(castable); + (void)castable; + return static_cast(shadowNode); +} + +template <> +inline LayoutableShadowNode const *traitCast( + ShadowNode const *shadowNode) { + bool castable = + shadowNode->getTraits().check(ShadowNodeTraits::Trait::LayoutableKind); + assert( + castable == + (dynamic_cast(shadowNode) != nullptr)); + if (!castable) { + return nullptr; + } + return static_cast(shadowNode); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 63ccdfcd866..e4482f469a2 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -194,5 +194,17 @@ class ShadowNode : public Sealable, public DebugStringConvertible { ShadowNodeTraits traits_; }; +/* + * Template declarations for future specializations in concrete classes. + * `traitCast` checks for a trait that corresponds to the provided type and + * performs `static_cast`. Practically, the behavior is identical to + * `dynamic_cast` with very little runtime overhead. + */ +template +ShadowNodeReferenceT traitCast(ShadowNode const &shadowNode); + +template +ShadowNodePointerT traitCast(ShadowNode const *shadowNode); + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp index f58e949952b..9f3388d882c 100644 --- a/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/LayoutableShadowNodeTest.cpp @@ -15,6 +15,9 @@ class LayoutableShadowNodeTest : public ::testing::Test { LayoutableShadowNodeTest() : eventDispatcher_(std::shared_ptr()), componentDescriptor_(TestComponentDescriptor({eventDispatcher_})) { + + auto traits = TestShadowNode::BaseTraits(); + auto familyA = std::make_shared( ShadowNodeFamilyFragment{ /* .tag = */ 9, @@ -30,7 +33,7 @@ class LayoutableShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyA, - ShadowNodeTraits{}); + traits); auto familyAA = std::make_shared( ShadowNodeFamilyFragment{ @@ -41,8 +44,8 @@ class LayoutableShadowNodeTest : public ::testing::Test { eventDispatcher_, componentDescriptor_); - auto traits = TestShadowNode::BaseTraits(); - traits.set(ShadowNodeTraits::Trait::RootNodeKind); + auto rootTraits = traits; + rootTraits.set(ShadowNodeTraits::Trait::RootNodeKind); nodeAA_ = std::make_shared( ShadowNodeFragment{ @@ -50,7 +53,7 @@ class LayoutableShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyAA, - traits); + rootTraits); auto familyAAA = std::make_shared( ShadowNodeFamilyFragment{ @@ -67,7 +70,7 @@ class LayoutableShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyAAA, - ShadowNodeTraits{}); + traits); nodeA_->appendChild(nodeAA_); nodeAA_->appendChild(nodeAAA_); diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 0a2e5525bb7..08e331a56fc 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -35,6 +35,8 @@ class ShadowNodeTest : public ::testing::Test { auto props = std::make_shared(); + auto traits = TestShadowNode::BaseTraits(); + auto familyAA = std::make_shared( ShadowNodeFamilyFragment{ /* .tag = */ 11, @@ -49,7 +51,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyAA, - ShadowNodeTraits{}); + traits); auto familyABA = std::make_shared( ShadowNodeFamilyFragment{ @@ -65,7 +67,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyABA, - ShadowNodeTraits{}); + traits); auto familyABB = std::make_shared( ShadowNodeFamilyFragment{ @@ -81,7 +83,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyABB, - ShadowNodeTraits{}); + traits); auto nodeABChildren = std::make_shared( SharedShadowNodeList{nodeABA_, nodeABB_}); @@ -100,7 +102,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ nodeABChildren, }, familyAB, - ShadowNodeTraits{}); + traits); auto familyAC = std::make_shared( ShadowNodeFamilyFragment{ @@ -116,7 +118,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyAC, - ShadowNodeTraits{}); + traits); auto nodeAChildren = std::make_shared( SharedShadowNodeList{nodeAA_, nodeAB_, nodeAC_}); @@ -135,7 +137,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ nodeAChildren, }, familyA, - ShadowNodeTraits{}); + traits); auto familyZ = std::make_shared( ShadowNodeFamilyFragment{ @@ -151,7 +153,7 @@ class ShadowNodeTest : public ::testing::Test { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), }, familyZ, - ShadowNodeTraits{}); + traits); } std::shared_ptr eventDispatcher_; @@ -239,6 +241,8 @@ TEST_F(ShadowNodeTest, handleState) { eventDispatcher_, componentDescriptor_); + auto traits = TestShadowNode::BaseTraits(); + auto props = std::make_shared(); auto fragment = ShadowNodeFragment{ /* .props = */ props, @@ -254,21 +258,21 @@ TEST_F(ShadowNodeTest, handleState) { /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), /* .state = */ initialState}, family, - ShadowNodeTraits{}); + traits); auto secondNode = std::make_shared( ShadowNodeFragment{ /* .props = */ props, /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), /* .state = */ initialState}, family, - ShadowNodeTraits{}); + traits); auto thirdNode = std::make_shared( ShadowNodeFragment{ /* .props = */ props, /* .children = */ ShadowNode::emptySharedShadowNodeSharedList(), /* .state = */ initialState}, family, - ShadowNodeTraits{}); + traits); TestShadowNode::ConcreteState::Shared _state = std::static_pointer_cast(