Files
react-native/ReactCommon/fabric/debug/DebugStringConvertibleItem.h
T
Valentin Shergin 432b434b55 Fabric: LayoutableShadowNode now inherits ShadowNode
Summary:
This is a very crucial change, everything else in this stack depends on it.
Here is the set of constraints that we have for ShadowNode-based class hierarchy:
* `ShadowNode` is a base class that defines basic operations on the nodes. It does not have virtual methods by design (virtual dispatch hurts performance; we want to limit and centralize that in `ComponentDescriptor`s).
* `ConcreteShadowNode<>` template *statically* wires particular `ShadowNode` and particular `Props` establishing a type-safe relationship between them ensured on compile time.
* Not all `ShadowNode`s are "layoutable", not all "layoutable" `ShadowNode`s use Yoga to do layout.
* Layotability (and YogaLayotability) feature is implemented as two classes `LayoutableShadowNode` and `YogaLayoutableShadowNode`. These classes essentially need to know something about the ShadowNode nature of the object (get the list of children or replace some children).

Before the change, `LayoutableShadowNode` and `YogaLayoutableShadowNode`classes did not inherit `ShadowNode` because we don't want to use *virtual inheritance* for `ShadowNode`: `ConcreteShadowNode<>` already inherits `ShadowNode`, so if we make `LayoutableShadowNode` inherits `ShadowNode`, we will have to somehow flatten this inheritance hierarchy (and the virtual inheritance is an answer to that). (Yes, C++ supports multiple inheritance and virtual inheritance.)
Before this change, we solved this dilemma this way: We have a subclass-template `ConcreteViewShadowNode<>` that inherits `ConcreteShadowNode<>` and `YogaLayoutableShadowNode`. Then, we had a bunch of methods that implement the rerouting of some functionality from `YogaLayoutableShadowNode` to `ShadowNode` and vise-versa. (See the diagram "Before".)

That worked fine, except the caveats:
* That wiring is nasty, complex, hard to reason about and overall limiting.
* There is no way to statically cast `LayoutableShadowNode` to `ShadowNode` (because there is no common base class). That forces us to use dynamic_cast on some perf critical paths (including layout, diffing and so on).
* Adding features that rely on interop between `LayoutableShadowNode` and `ShadowNode` is a nightmare.

It should be a better way to deal with this dilemma, and this diff implements a different approach: We can have a base class of `ConcreteShadowNode<>` as a template parameter. With this approach, we can make `LayoutableShadowNode` inherit `ShadowNode` and when we need to instantiate a `ConcreteShadowNode<>` that needs to be layoutable, we can just specify `YogaLayoutableShadowNode` as a base class. (See the diagram "After".)

This simple change will allow us to simplify a lot of things. The rest of the stack is about getting rid of unnecessary moving parts. Which will finally allow us to build "Inline Views" feature.

```
╭──────────────────────╮
│ ◎ ○ ○ ░░░░░░░░░░░░░░░│
├──────────────────────┤
│                      │
│                      │
│        Before        │
│                      │              ┌────────────────────────────┐       ┌────────────────────────────┐
│                      │              │                            │       │                            │
│                      │              │         ShadowNode         │       │    LayoutableShadowNode    │
└──────────────────────┘              │                            │       │                            │
                                      └────────────────────────────┘       └────────────────────────────┘
                                                     ▲                                    ▲
                                                     │                                    │
                                      ╔════════════════════════════╗       ┌────────────────────────────┐
                                      ║                            ║       │                            │
                            ┌────────�║    ConcreteShadowNode<>    ║       │  YogaLayoutableShadowNode  │
                            │         ║                            ║       │                            │
                            │         ╚════════════════════════════╝       └────────────────────────────┘
                            │                        ▲                                    ▲
                            │                        │                                    │
                            │                        │                                    │
                            │                        │                                    │
                            │                        │     ╔════════════════════════════╗ │
                            │                        │     ║                            ║ │
                            │                        └─────║  ConcreteViewShadowNode<>  ║─┘
                            │                              ║                            ║
                            │                              ╚════════════════════════════╝
                            │                                             ▲
                            │                                             │
                            │                              ┌──────────────┴───────────────┐
                            │                              │                              │
                            │                              │                              │
                            │                              │                              │
             ┌────────────────────────────┐ ┌────────────────────────────┐ ┌────────────────────────────┐
             │                            │ │                            │ │                            │
             │       TextShadowNode       │ │       ViewShadowNode       │ │    ParagraphShadowNode     │
             │                            │ │                            │ │                            │
             └────────────────────────────┘ └────────────────────────────┘ └────────────────────────────┘

╭──────────────────────╮
│ ◎ ○ ○ ░░░░░░░░░░░░░░░│
├──────────────────────┤
│                      │                           ┌────────────────────────────┐
│                      │                           │                            │
│        After         │                           │         ShadowNode         │
│                      │                           │                            │
│                      │                           └────────────────────────────┘
│                      │                                          ▲
└──────────────────────┘     ┌────────────────────────────────────┤
                             │                                    │
                             │                     ╔════════════════════════════╗
              ┌────────────────────────────┐       ║     ConcreteShadowNode     ║
              │                            │       ║     <Base: ShadowNode>     ║
              │    LayoutableShadowNode    │       ║                            ║
              │                            │       ╚════════════════════════════╝
              └────────────────────────────┘                      ▲
                             ▲                                    │
                             │                     ┌────────────────────────────┐
              ┌────────────────────────────┐       │                            │
              │                            │       │       TextShadowNode       │
              │  YogaLayoutableShadowNode  │       │                            │
              │                            │       └────────────────────────────┘
              └────────────────────────────┘
                             ▲
                             │
              ╔════════════════════════════╗
              ║     ConcreteShadowNode     ║
              ║           <Base:           ║
              ║ YogaLayoutableShadowNode>  ║
              ╚════════════════════════════╝
                             ▲
                             │
              ╔════════════════════════════╗
              ║                            ║
              ║  ConcreteViewShadowNode<>  ║
              ║                            ║
              ╚════════════════════════════╝
                             ▲
                             ├─────────────────────────────────────┐
                             │                                     │
              ┌────────────────────────────┐        ┌────────────────────────────┐
              │                            │        │                            │
              │    ParagraphShadowNode     │        │       ViewShadowNode       │
              │                            │        │                            │
              └────────────────────────────┘        └────────────────────────────┘

```

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D19963353

fbshipit-source-id: b65c8a5064bdb54ab64f08a8e546aa9e2b5a486b
2020-02-26 22:08:16 -08:00

48 lines
1.3 KiB
C++

/*
* 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 <string>
#include <react/debug/DebugStringConvertible.h>
namespace facebook {
namespace react {
#if RN_DEBUG_STRING_CONVERTIBLE
// Trivial implementation of `DebugStringConvertible` abstract class
// with a stored output; useful for assembling `DebugStringConvertible` values
// in custom implementations of `getDebugChildren` and `getDebugProps`.
class DebugStringConvertibleItem : public DebugStringConvertible {
public:
DebugStringConvertibleItem(const DebugStringConvertibleItem &item) = default;
DebugStringConvertibleItem(
const std::string &name = "",
const std::string &value = "",
const SharedDebugStringConvertibleList &props = {},
const SharedDebugStringConvertibleList &children = {});
std::string getDebugName() const override;
std::string getDebugValue() const override;
SharedDebugStringConvertibleList getDebugChildren() const override;
SharedDebugStringConvertibleList getDebugProps() const override;
private:
std::string name_;
std::string value_;
SharedDebugStringConvertibleList debugProps_;
SharedDebugStringConvertibleList children_;
};
#endif
} // namespace react
} // namespace facebook