From 9842e39019c98d4142e272ff17c500fdcb59376e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 6 Feb 2019 16:12:45 -0800 Subject: [PATCH] Fabric: folly::dynamic was replaced with RawValue in prop-parsing infra Summary: Our long-term plan is to completely illuminate `jsi::Value`-to-`folly::dynamic` serialization step in prop parsing process improving performance and memory pressure. At the same time, we don't want to introduce a hard dependency in application code to JSI because it exposes direct access to VM and prevents parsing some data that come *NOT* from JSVM. RawValue is an extremely light-weight (hopefully fully optimized-out) abstraction that provides limited JSON-like and C++-idiomatic interface. The current particular implementation is still using `folly::dynamic` inside, but I have fully JSI-powered one which will replace the current one right after we figure out how to deal with folly::dynamic-specific callsites. Or we can implement RawValue in a hybrid manner if a code-size implication of that will be minimal. Reviewed By: JoshuaGross, mdvacca Differential Revision: D13962466 fbshipit-source-id: e848522fd242f21e9e771773f2103f1c1d9d7f21 --- .../facebook/react/fabric/jsi/jni/Binding.cpp | 6 +- .../fabric/attributedstring/conversions.h | 56 ++-- .../activityindicator/conversions.h | 6 +- .../fabric/components/image/conversions.h | 40 +-- .../components/scrollview/conversions.h | 18 +- .../accessibilityPropsConversions.h | 16 +- .../fabric/components/view/conversions.h | 176 ++++++------ .../fabric/core/primitives/RawProps.cpp | 8 + ReactCommon/fabric/core/primitives/RawProps.h | 97 +++++++ .../fabric/core/primitives/RawValue.cpp | 8 + ReactCommon/fabric/core/primitives/RawValue.h | 266 ++++++++++++++++++ .../fabric/core/primitives/ReactPrimitives.h | 12 +- ReactCommon/fabric/core/propsConversions.h | 75 +++-- ReactCommon/fabric/core/shadownode/Props.cpp | 2 +- ReactCommon/fabric/core/shadownode/Props.h | 2 +- .../core/tests/ComponentDescriptorTest.cpp | 9 +- .../fabric/core/tests/ShadowNodeTest.cpp | 3 +- ReactCommon/fabric/core/tests/TestComponent.h | 4 +- ReactCommon/fabric/graphics/conversions.h | 119 ++++---- .../uimanager/ComponentDescriptorRegistry.cpp | 3 +- ReactCommon/fabric/uimanager/UIManager.cpp | 9 +- ReactCommon/fabric/uimanager/UIManager.h | 2 +- .../fabric/uimanager/UIManagerBinding.cpp | 10 +- ReactCommon/fabric/uimanager/primitives.h | 24 -- codegen/src/generators/GeneratePropsH.js | 4 +- .../__snapshots__/GeneratePropsH-test.js.snap | 4 +- 26 files changed, 660 insertions(+), 319 deletions(-) create mode 100644 ReactCommon/fabric/core/primitives/RawProps.cpp create mode 100644 ReactCommon/fabric/core/primitives/RawProps.h create mode 100644 ReactCommon/fabric/core/primitives/RawValue.cpp create mode 100644 ReactCommon/fabric/core/primitives/RawValue.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 77ec29f27..31410c43a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -171,11 +171,7 @@ local_ref createUpdatePropsMountItem(const jni::global_r auto newViewProps = *std::dynamic_pointer_cast(shadowView.props); // TODO: move props from map to a typed object. - auto rawProps = shadowView.props->rawProps; - folly::dynamic newProps = folly::dynamic::object(); - for (auto element : rawProps) { - newProps[element.first] = element.second; - } + auto newProps = shadowView.props->rawProps; local_ref readableMap = ReadableNativeMap::newObjectCxxArgs(newProps); diff --git a/ReactCommon/fabric/attributedstring/conversions.h b/ReactCommon/fabric/attributedstring/conversions.h index ffec2ea89..2dfea3773 100644 --- a/ReactCommon/fabric/attributedstring/conversions.h +++ b/ReactCommon/fabric/attributedstring/conversions.h @@ -36,8 +36,8 @@ inline std::string toString(const EllipsizeMode &ellipsisMode) { } } -inline void fromDynamic(const folly::dynamic &value, EllipsizeMode &result) { - auto string = value.getString(); +inline void fromRawValue(const RawValue &value, EllipsizeMode &result) { + auto string = (std::string)value; if (string == "clip") { result = EllipsizeMode::Clip; return; @@ -57,8 +57,8 @@ inline void fromDynamic(const folly::dynamic &value, EllipsizeMode &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, FontWeight &result) { - auto string = value.asString(); +inline void fromRawValue(const RawValue &value, FontWeight &result) { + auto string = (std::string)value; if (string == "normal") { result = FontWeight::Regular; return; @@ -114,8 +114,8 @@ inline std::string toString(const FontWeight &fontWeight) { return folly::to((int)fontWeight); } -inline void fromDynamic(const folly::dynamic &value, FontStyle &result) { - auto string = value.asString(); +inline void fromRawValue(const RawValue &value, FontStyle &result) { + auto string = (std::string)value; if (string == "normal") { result = FontStyle::Normal; return; @@ -142,28 +142,28 @@ inline std::string toString(const FontStyle &fontStyle) { } } -inline void fromDynamic(const folly::dynamic &value, FontVariant &result) { - assert(value.isArray()); +inline void fromRawValue(const RawValue &value, FontVariant &result) { + assert(value.hasType>()); result = FontVariant::Default; - for (auto &&item : value) { - auto string = item.asString(); - if (string == "small-caps") { + auto items = std::vector{value}; + for (const auto &item : items) { + if (item == "small-caps") { result = (FontVariant)((int)result | (int)FontVariant::SmallCaps); continue; } - if (string == "oldstyle-nums") { + if (item == "oldstyle-nums") { result = (FontVariant)((int)result | (int)FontVariant::OldstyleNums); continue; } - if (string == "lining-nums") { + if (item == "lining-nums") { result = (FontVariant)((int)result | (int)FontVariant::LiningNums); continue; } - if (string == "tabular-nums") { + if (item == "tabular-nums") { result = (FontVariant)((int)result | (int)FontVariant::TabularNums); continue; } - if (string == "proportional-nums") { + if (item == "proportional-nums") { result = (FontVariant)((int)result | (int)FontVariant::ProportionalNums); continue; } @@ -196,8 +196,8 @@ inline std::string toString(const FontVariant &fontVariant) { return result; } -inline void fromDynamic(const folly::dynamic &value, TextAlignment &result) { - auto string = value.asString(); +inline void fromRawValue(const RawValue &value, TextAlignment &result) { + auto string = (std::string)value; if (string == "natural") { result = TextAlignment::Natural; return; @@ -236,8 +236,8 @@ inline std::string toString(const TextAlignment &textAlignment) { } } -inline void fromDynamic(const folly::dynamic &value, WritingDirection &result) { - auto string = value.asString(); +inline void fromRawValue(const RawValue &value, WritingDirection &result) { + auto string = (std::string)value; if (string == "natural") { result = WritingDirection::Natural; return; @@ -264,10 +264,10 @@ inline std::string toString(const WritingDirection &writingDirection) { } } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, TextDecorationLineType &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "none") { result = TextDecorationLineType::None; return; @@ -301,10 +301,10 @@ inline std::string toString( } } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, TextDecorationLineStyle &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "single") { result = TextDecorationLineStyle::Single; return; @@ -332,10 +332,10 @@ inline std::string toString( } } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, TextDecorationLinePattern &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "solid") { result = TextDecorationLinePattern::Solid; return; diff --git a/ReactCommon/fabric/components/activityindicator/conversions.h b/ReactCommon/fabric/components/activityindicator/conversions.h index 3982cb5e3..d84b7a75c 100644 --- a/ReactCommon/fabric/components/activityindicator/conversions.h +++ b/ReactCommon/fabric/components/activityindicator/conversions.h @@ -13,10 +13,10 @@ namespace facebook { namespace react { -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, ActivityIndicatorViewSize &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "large") { result = ActivityIndicatorViewSize::Large; return; diff --git a/ReactCommon/fabric/components/image/conversions.h b/ReactCommon/fabric/components/image/conversions.h index 5943eb283..015c8f01d 100644 --- a/ReactCommon/fabric/components/image/conversions.h +++ b/ReactCommon/fabric/components/image/conversions.h @@ -14,41 +14,43 @@ namespace facebook { namespace react { -inline void fromDynamic(const folly::dynamic &value, ImageSource &result) { - if (value.isString()) { - result = {.type = ImageSource::Type::Remote, .uri = value.asString()}; +inline void fromRawValue(const RawValue &value, ImageSource &result) { + if (value.hasType()) { + result = {.type = ImageSource::Type::Remote, .uri = (std::string)value}; return; } - if (value.isObject()) { + if (value.hasType>()) { + auto items = (std::unordered_map)value; result = {}; result.type = ImageSource::Type::Remote; - if (value.count("__packager_asset")) { + if (items.find("__packager_asset") != items.end()) { result.type = ImageSource::Type::Local; } - if (value.count("width") && value.count("height")) { - fromDynamic(value, result.size); + if (items.find("width") != items.end() && + items.find("height") != items.end()) { + result.size = {(Float)items.at("width"), (Float)items.at("height")}; } - if (value.count("scale")) { - result.scale = (Float)value["scale"].asDouble(); + if (items.find("scale") != items.end()) { + result.scale = (Float)items.at("scale"); } else { - result.scale = value.count("deprecated") ? 0.0 : 1.0; + result.scale = items.find("deprecated") != items.end() ? 0.0 : 1.0; } - if (value.count("url")) { - result.uri = value["url"].asString(); + if (items.find("url") != items.end()) { + result.uri = (std::string)items.at("url"); } - if (value.count("uri")) { - result.uri = value["uri"].asString(); + if (items.find("uri") != items.end()) { + result.uri = (std::string)items.at("uri"); } - if (value.count("bundle")) { - result.bundle = value["bundle"].asString(); + if (items.find("bundle") != items.end()) { + result.bundle = (std::string)items.at("bundle"); result.type = ImageSource::Type::Local; } @@ -62,9 +64,9 @@ inline std::string toString(const ImageSource &value) { return "{uri: " + value.uri + "}"; } -inline void fromDynamic(const folly::dynamic &value, ImageResizeMode &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, ImageResizeMode &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "cover") { result = ImageResizeMode::Cover; return; diff --git a/ReactCommon/fabric/components/scrollview/conversions.h b/ReactCommon/fabric/components/scrollview/conversions.h index d5c2d5acd..bcbcaaac3 100644 --- a/ReactCommon/fabric/components/scrollview/conversions.h +++ b/ReactCommon/fabric/components/scrollview/conversions.h @@ -13,10 +13,10 @@ namespace facebook { namespace react { -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, ScrollViewSnapToAlignment &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "start") { result = ScrollViewSnapToAlignment::Start; return; @@ -32,10 +32,10 @@ inline void fromDynamic( abort(); } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, ScrollViewIndicatorStyle &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "default") { result = ScrollViewIndicatorStyle::Default; return; @@ -51,10 +51,10 @@ inline void fromDynamic( abort(); } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, ScrollViewKeyboardDismissMode &result) { - auto string = value.asString(); + auto string = (std::string)value; if (string == "none") { result = ScrollViewKeyboardDismissMode::None; return; diff --git a/ReactCommon/fabric/components/view/accessibility/accessibilityPropsConversions.h b/ReactCommon/fabric/components/view/accessibility/accessibilityPropsConversions.h index 4e7c36192..4125f3835 100644 --- a/ReactCommon/fabric/components/view/accessibility/accessibilityPropsConversions.h +++ b/ReactCommon/fabric/components/view/accessibility/accessibilityPropsConversions.h @@ -81,20 +81,18 @@ inline void fromString(const std::string &string, AccessibilityTraits &result) { abort(); } -inline void fromDynamic( - const folly::dynamic &value, - AccessibilityTraits &result) { - if (value.isString()) { - fromString(value.asString(), result); +inline void fromRawValue(const RawValue &value, AccessibilityTraits &result) { + if (value.hasType()) { + fromString((std::string)value, result); return; } - if (value.isArray()) { + if (value.hasType>()) { result = {}; - for (auto &item : value) { - auto string = item.asString(); + auto items = (std::vector)value; + for (auto &item : items) { AccessibilityTraits itemAccessibilityTraits; - fromString(value.asString(), itemAccessibilityTraits); + fromString(item, itemAccessibilityTraits); result = result | itemAccessibilityTraits; } } diff --git a/ReactCommon/fabric/components/view/conversions.h b/ReactCommon/fabric/components/view/conversions.h index 4a4eaa5ea..957b4ab42 100644 --- a/ReactCommon/fabric/components/view/conversions.h +++ b/ReactCommon/fabric/components/view/conversions.h @@ -126,9 +126,9 @@ inline YGDirection yogaDirectionFromLayoutDirection(LayoutDirection direction) { } } -inline void fromDynamic(const folly::dynamic &value, YGDirection &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGDirection &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "inherit") { result = YGDirectionInherit; return; @@ -144,9 +144,9 @@ inline void fromDynamic(const folly::dynamic &value, YGDirection &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGFlexDirection &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGFlexDirection &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "column") { result = YGFlexDirectionColumn; return; @@ -166,9 +166,9 @@ inline void fromDynamic(const folly::dynamic &value, YGFlexDirection &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGJustify &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGJustify &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "flex-start") { result = YGJustifyFlexStart; return; @@ -196,9 +196,9 @@ inline void fromDynamic(const folly::dynamic &value, YGJustify &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGAlign &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGAlign &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "auto") { result = YGAlignAuto; return; @@ -234,9 +234,9 @@ inline void fromDynamic(const folly::dynamic &value, YGAlign &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGPositionType &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGPositionType &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "relative") { result = YGPositionTypeRelative; return; @@ -248,9 +248,9 @@ inline void fromDynamic(const folly::dynamic &value, YGPositionType &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGWrap &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGWrap &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "no-wrap") { result = YGWrapNoWrap; return; @@ -266,9 +266,9 @@ inline void fromDynamic(const folly::dynamic &value, YGWrap &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGOverflow &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGOverflow &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "visible") { result = YGOverflowVisible; return; @@ -284,9 +284,9 @@ inline void fromDynamic(const folly::dynamic &value, YGOverflow &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, YGDisplay &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, YGDisplay &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "flex") { result = YGDisplayFlex; return; @@ -298,14 +298,14 @@ inline void fromDynamic(const folly::dynamic &value, YGDisplay &result) { abort(); } -inline void fromDynamic( - const folly::dynamic &value, +inline void fromRawValue( + const RawValue &value, decltype(YGStyle{}.margin[0]) /* type is subject to change */ &result) { - if (value.isNumber()) { - result = yogaStyleValueFromFloat(value.asDouble()); + if (value.hasType()) { + result = yogaStyleValueFromFloat((Float)value); return; - } else if (value.isString()) { - const auto stringValue = value.asString(); + } else if (value.hasType()) { + const auto stringValue = (std::string)value; if (stringValue == "auto") { result = YGValueUndefined; return; @@ -324,12 +324,12 @@ inline void fromDynamic( result = YGValueUndefined; } -inline void fromDynamic(const folly::dynamic &value, YGFloatOptional &result) { - if (value.isNumber()) { - result = YGFloatOptional(value.asDouble()); +inline void fromRawValue(const RawValue &value, YGFloatOptional &result) { + if (value.hasType()) { + result = YGFloatOptional((float)value); return; - } else if (value.isString()) { - const auto stringValue = value.asString(); + } else if (value.hasType()) { + const auto stringValue = (std::string)value; if (stringValue == "auto") { result = YGFloatOptional(); return; @@ -338,76 +338,74 @@ inline void fromDynamic(const folly::dynamic &value, YGFloatOptional &result) { abort(); } -inline void fromDynamic(const folly::dynamic &value, Transform &result) { - assert(value.isArray()); +inline void fromRawValue(const RawValue &value, Transform &result) { + assert(value.hasType>()); auto transformMatrix = Transform{}; - for (const auto &tranformConfiguration : value) { - assert(tranformConfiguration.isObject()); - auto pair = *tranformConfiguration.items().begin(); - const auto &operation = pair.first.asString(); - const auto ¶meters = pair.second; + auto configurations = (std::vector)value; + + for (const auto &configuration : configurations) { + auto configurationPair = + (std::unordered_map)configuration; + auto pair = configurationPair.begin(); + auto operation = pair->first; + auto ¶meters = pair->second; if (operation == "matrix") { - assert(parameters.isArray()); - assert(parameters.size() == transformMatrix.matrix.size()); + assert(parameters.hasType>()); + auto numbers = (std::vector)parameters; + assert(numbers.size() == transformMatrix.matrix.size()); auto i = 0; - for (auto item : parameters) { - transformMatrix.matrix[i++] = (Float)item.asDouble(); + for (auto number : numbers) { + transformMatrix.matrix[i++] = number; } } else if (operation == "perspective") { - transformMatrix = transformMatrix * - Transform::Perspective((Float)parameters.asDouble()); - } else if (operation == "rotateX") { - transformMatrix = transformMatrix * - Transform::Rotate((Float)parameters.asDouble(), 0, 0); - } else if (operation == "rotateY") { - transformMatrix = transformMatrix * - Transform::Rotate(0, (Float)parameters.asDouble(), 0); - } else if (operation == "rotateZ") { - transformMatrix = transformMatrix * - Transform::Rotate(0, 0, (Float)parameters.asDouble()); - } else if (operation == "scale") { - transformMatrix = transformMatrix * - Transform::Scale((Float)parameters.asDouble(), - (Float)parameters.asDouble(), - (Float)parameters.asDouble()); - } else if (operation == "scaleX") { - transformMatrix = transformMatrix * - Transform::Scale((Float)parameters.asDouble(), 0, 0); - } else if (operation == "scaleY") { - transformMatrix = transformMatrix * - Transform::Scale(0, (Float)parameters.asDouble(), 0); - } else if (operation == "scaleZ") { - transformMatrix = transformMatrix * - Transform::Scale(0, 0, (Float)parameters.asDouble()); - } else if (operation == "translate") { transformMatrix = - transformMatrix * - Transform::Translate( - parameters[0].asDouble(), parameters[1].asDouble(), 0); + transformMatrix * Transform::Perspective((Float)parameters); + } else if (operation == "rotateX") { + transformMatrix = + transformMatrix * Transform::Rotate((Float)parameters, 0, 0); + } else if (operation == "rotateY") { + transformMatrix = + transformMatrix * Transform::Rotate(0, (Float)parameters, 0); + } else if (operation == "rotateZ") { + transformMatrix = + transformMatrix * Transform::Rotate(0, 0, (Float)parameters); + } else if (operation == "scale") { + auto number = (Float)parameters; + transformMatrix = + transformMatrix * Transform::Scale(number, number, number); + } else if (operation == "scaleX") { + transformMatrix = + transformMatrix * Transform::Scale((Float)parameters, 0, 0); + } else if (operation == "scaleY") { + transformMatrix = + transformMatrix * Transform::Scale(0, (Float)parameters, 0); + } else if (operation == "scaleZ") { + transformMatrix = + transformMatrix * Transform::Scale(0, 0, (Float)parameters); + } else if (operation == "translate") { + auto numbers = (std::vector)parameters; + transformMatrix = transformMatrix * + Transform::Translate(numbers.at(0), numbers.at(1), 0); } else if (operation == "translateX") { transformMatrix = - transformMatrix * Transform::Translate(parameters.asDouble(), 0, 0); + transformMatrix * Transform::Translate((Float)parameters, 0, 0); } else if (operation == "translateY") { transformMatrix = - transformMatrix * Transform::Translate(0, parameters.asDouble(), 0); + transformMatrix * Transform::Translate(0, (Float)parameters, 0); } else if (operation == "skewX") { - transformMatrix = - transformMatrix * Transform::Skew(parameters.asDouble(), 0); + transformMatrix = transformMatrix * Transform::Skew((Float)parameters, 0); } else if (operation == "skewY") { - transformMatrix = - transformMatrix * Transform::Skew(0, parameters.asDouble()); + transformMatrix = transformMatrix * Transform::Skew(0, (Float)parameters); } } result = transformMatrix; } -inline void fromDynamic( - const folly::dynamic &value, - PointerEventsMode &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, PointerEventsMode &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "auto") { result = PointerEventsMode::Auto; return; @@ -427,9 +425,9 @@ inline void fromDynamic( abort(); } -inline void fromDynamic(const folly::dynamic &value, BorderStyle &result) { - assert(value.isString()); - auto stringValue = value.asString(); +inline void fromRawValue(const RawValue &value, BorderStyle &result) { + assert(value.hasType()); + auto stringValue = (std::string)value; if (stringValue == "solid") { result = BorderStyle::Solid; return; diff --git a/ReactCommon/fabric/core/primitives/RawProps.cpp b/ReactCommon/fabric/core/primitives/RawProps.cpp new file mode 100644 index 000000000..a647a379f --- /dev/null +++ b/ReactCommon/fabric/core/primitives/RawProps.cpp @@ -0,0 +1,8 @@ +/** + * 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 "RawProps.h" diff --git a/ReactCommon/fabric/core/primitives/RawProps.h b/ReactCommon/fabric/core/primitives/RawProps.h new file mode 100644 index 000000000..6feed6afa --- /dev/null +++ b/ReactCommon/fabric/core/primitives/RawProps.h @@ -0,0 +1,97 @@ +/** + * 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 +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * `RawProps` represents an untyped map of props comes from JavaScript side. + * `RawProps` stores JSI (or `folly::dynamic`) primitives inside and abstract + * them as `RawValue` objects. + * `RawProps` is NOT a thread-safe type nor long-living type. + * The caller must not store values of this type. + * The class is practically a wrapper around a `jsi::Value and `jsi::Runtime` + * pair (or folly::dynamic) preventing direct access to it and inefficient + * misuse. Not copyable, not moveable. + */ +class RawProps { + public: + /* + * Creates an object with given `runtime` and `value`. + */ + RawProps(jsi::Runtime &runtime, const jsi::Value &value) noexcept + : RawProps( + value.isNull() ? folly::dynamic::object() + : jsi::dynamicFromValue(runtime, value)) {} + + /* + * Creates an object with given `folly::dynamic` object. + * Deprecated. + * We need this temporary, only because we have a callsite that does not have + * a `jsi::Runtime` behind the data. + */ + RawProps(const folly::dynamic &dynamic) noexcept + : +#ifdef ANDROID + dynamic_(dynamic), +#endif + map_((std::unordered_map)RawValue(dynamic)) { + } + + /* + * Not moveable. + */ + RawProps(RawProps &&other) noexcept = delete; + RawProps &operator=(RawProps &&other) noexcept = delete; + + /* + * Not copyable. + */ + RawProps(const RawProps &other) noexcept = delete; + RawProps &operator=(const RawProps &other) noexcept = delete; + +#ifdef ANDROID + /* + * Deprecated. Do not use. + * The support for explicit conversion to `folly::dynamic` is deprecated and + * will be removed as soon Android implementation does not need it. + */ + explicit operator folly::dynamic() const noexcept { + return dynamic_; + } +#endif + + /* + * Returns a const unowning pointer to `RawValue` of a prop with a given name. + * Returns `nullptr`, it a prop with the given name does not exist. + */ + const RawValue *at(const std::string &name) const noexcept { + auto iterator = map_.find(name); + if (iterator == map_.end()) { + return nullptr; + } + + return &iterator->second; + } + + private: +#ifdef ANDROID + const folly::dynamic dynamic_; +#endif + + const std::unordered_map map_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/primitives/RawValue.cpp b/ReactCommon/fabric/core/primitives/RawValue.cpp new file mode 100644 index 000000000..9457cc767 --- /dev/null +++ b/ReactCommon/fabric/core/primitives/RawValue.cpp @@ -0,0 +1,8 @@ +/** + * 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 "RawValue.h" diff --git a/ReactCommon/fabric/core/primitives/RawValue.h b/ReactCommon/fabric/core/primitives/RawValue.h new file mode 100644 index 000000000..c7acfa9bc --- /dev/null +++ b/ReactCommon/fabric/core/primitives/RawValue.h @@ -0,0 +1,266 @@ +/** + * 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 +#include +#include + +namespace facebook { +namespace react { + +class RawProps; + +/* + * `RawValue` abstracts some arbitrary complex data structure similar to JSON. + * `RawValue` supports explicit conversion to: `bool`, `int`, `int64_t`, + * `float`, `double`, `string`, and `vector` & `map` of those types and itself. + * + * The main intention of the class is to abstract React props parsing infra from + * JSI, to enable support for any non-JSI-based data sources. The particular + * implementation of the interface is a very slim abstraction around + * `folly::dynamic` though. + * In the near future, this class will hold a `jsi::Runtime` and `jsi::Value` + * pair instead of `folly::dynamic`. + * + * How `RawValue` is different from `JSI::Value`: + * * `RawValue` provides much more scoped API without any references to + * JavaScript specifics. + * * The API is much more C++-idiomatic and easy to use from C++ code. + * * The API prevents access to JSI/JavaScript internals from prop-parsing + * code. + * * The `RawValue` is not copyable nor thread-safe, which prevent + * misuse and accidental performance problems. + * + * How `RawValue` is different from `folly::dynamic`: + * * `RawValue` is a lazy data structure, it does not copy all content inside, + * it provides efficient SAX-like access to the data. + * * `RawValue` has more static and C++-idiomatic API. + * * The `RawValue` is not copyable nor thread-safe, which prevent + * misuse and accidental performance problems. + */ +class RawValue { + public: + /* + * Constructors. + */ + RawValue() noexcept : dynamic_(nullptr){}; + + RawValue(RawValue &&other) noexcept : dynamic_(std::move(other.dynamic_)) {} + + RawValue &operator=(RawValue &&other) noexcept { + if (this != &other) { + dynamic_ = std::move(other.dynamic_); + } + return *this; + } + + private: + friend RawProps; + + /* + * Arbitrary constructors are private only for RawProps and internal usage. + */ + RawValue(const folly::dynamic &dynamic) noexcept : dynamic_(dynamic){}; + + RawValue(folly::dynamic &&dynamic) noexcept : dynamic_(std::move(dynamic)){}; + + /* + * Copy constructor and copy assignment operator are private and only for + * internal use. Basically, it's implementation details. Other particular + * implementations of the `RawValue` interface may not have them. + */ + RawValue(RawValue const &other) noexcept : dynamic_(other.dynamic_) {} + + RawValue &operator=(const RawValue &other) noexcept { + if (this != &other) { + dynamic_ = other.dynamic_; + } + return *this; + } + + public: + /* + * Casts the value to a specified type. + */ + template + explicit operator T() const noexcept { + return castValue(dynamic_, (T *)nullptr); + } + + inline explicit operator folly::dynamic() const { + return dynamic_; + } + + /* + * Checks if the stored value has specified type. + */ + template + bool hasType() const noexcept { + return checkValueType(dynamic_, (T *)nullptr); + }; + + /* + * Checks if the stored value is *not* `null`. + */ + bool hasValue() const noexcept { + return !dynamic_.isNull(); + } + + private: + folly::dynamic dynamic_; + + static bool checkValueType( + const folly::dynamic &dynamic, + RawValue *type) noexcept { + return true; + } + + static bool checkValueType( + const folly::dynamic &dynamic, + bool *type) noexcept { + return dynamic.isBool(); + } + + static bool checkValueType( + const folly::dynamic &dynamic, + int *type) noexcept { + return dynamic.isNumber(); + } + + static bool checkValueType( + const folly::dynamic &dynamic, + int64_t *type) noexcept { + return dynamic.isNumber(); + } + + static bool checkValueType( + const folly::dynamic &dynamic, + float *type) noexcept { + return dynamic.isNumber(); + } + + static bool checkValueType( + const folly::dynamic &dynamic, + double *type) noexcept { + return dynamic.isNumber(); + } + + static bool checkValueType( + const folly::dynamic &dynamic, + std::string *type) noexcept { + return dynamic.isString(); + } + + template + static bool checkValueType( + const folly::dynamic &dynamic, + std::vector *type) noexcept { + if (!dynamic.isArray()) { + return false; + } + + for (const auto &item : dynamic) { + if (!checkValueType(item, (T *)nullptr)) { + return false; + } + + // Note: We test only one element. + break; + } + + return true; + } + + template + static bool checkValueType( + const folly::dynamic &dynamic, + std::unordered_map *type) noexcept { + if (!dynamic.isObject()) { + return false; + } + + for (const auto &item : dynamic.items()) { + assert(item.first.isString()); + if (!checkValueType(item.second, (T *)nullptr)) { + return false; + } + + // Note: We test only one element. + break; + } + + return true; + } + + // Casts + static RawValue castValue( + const folly::dynamic &dynamic, + RawValue *type) noexcept { + return RawValue(dynamic); + } + + static bool castValue(const folly::dynamic &dynamic, bool *type) noexcept { + return dynamic.getBool(); + } + + static int castValue(const folly::dynamic &dynamic, int *type) noexcept { + return dynamic.asInt(); + } + + static int64_t castValue( + const folly::dynamic &dynamic, + int64_t *type) noexcept { + return dynamic.asInt(); + } + + static float castValue(const folly::dynamic &dynamic, float *type) noexcept { + return dynamic.asDouble(); + } + + static double castValue( + const folly::dynamic &dynamic, + double *type) noexcept { + return dynamic.asDouble(); + } + + static std::string castValue( + const folly::dynamic &dynamic, + std::string *type) noexcept { + return dynamic.getString(); + } + + template + static std::vector castValue( + const folly::dynamic &dynamic, + std::vector *type) noexcept { + assert(dynamic.isArray()); + auto result = std::vector{}; + result.reserve(dynamic.size()); + for (const auto &item : dynamic) { + result.push_back(castValue(item, (T *)nullptr)); + } + return result; + } + + template + static std::unordered_map castValue( + const folly::dynamic &dynamic, + std::unordered_map *type) noexcept { + assert(dynamic.isObject()); + auto result = std::unordered_map{}; + for (const auto &item : dynamic.items()) { + assert(item.first.isString()); + result[item.first.getString()] = castValue(item.second, (T *)nullptr); + } + return result; + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/primitives/ReactPrimitives.h b/ReactCommon/fabric/core/primitives/ReactPrimitives.h index 296266e1b..54ca67d97 100644 --- a/ReactCommon/fabric/core/primitives/ReactPrimitives.h +++ b/ReactCommon/fabric/core/primitives/ReactPrimitives.h @@ -7,12 +7,13 @@ #pragma once +#include +#include +#include #include #include #include -#include - namespace facebook { namespace react { @@ -28,13 +29,6 @@ using InstanceHandle = struct InstanceHandleDummyStruct { */ using SurfaceId = int32_t; -/* - * `RawProps` represents untyped map with props comes from JavaScript side. - */ -// TODO(T26954420): Use iterator as underlying type for RawProps. -using RawProps = std::unordered_map; -using SharedRawProps = std::shared_ptr; - /* * Universal component handle which allows to refer to `ComponentDescriptor`s * in maps efficiently. diff --git a/ReactCommon/fabric/core/propsConversions.h b/ReactCommon/fabric/core/propsConversions.h index c95fdb945..003d9ab64 100644 --- a/ReactCommon/fabric/core/propsConversions.h +++ b/ReactCommon/fabric/core/propsConversions.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -16,90 +17,78 @@ namespace facebook { namespace react { -inline void fromDynamic(const folly::dynamic &value, bool &result) { - result = value.getBool(); -} -inline void fromDynamic(const folly::dynamic &value, int &result) { - // All numbers from JS are treated as double, and JS cannot represent int64 in - // practice. So this always converts the value to int64 instead. - result = value.asInt(); -} -inline void fromDynamic(const folly::dynamic &value, float &result) { - result = (float)value.asDouble(); -} -inline void fromDynamic(const folly::dynamic &value, double &result) { - result = value.asDouble(); -} -inline void fromDynamic(const folly::dynamic &value, std::string &result) { - result = value.getString(); -} -inline void fromDynamic(const folly::dynamic &value, folly::dynamic &result) { - result = value; +template +void fromRawValue(const RawValue &rawValue, T &result) { + result = (T)rawValue; } template -inline void fromDynamic(const folly::dynamic &value, std::vector &result) { - if (!value.isArray()) { - T itemResult; - fromDynamic(value, itemResult); - result = {itemResult}; +void fromRawValue(const RawValue &rawValue, std::vector &result) { + if (rawValue.hasType>()) { + auto items = (std::vector)rawValue; + auto length = items.size(); + result.clear(); + result.reserve(length); + for (int i = 0; i < length; i++) { + T itemResult; + fromRawValue(items.at(i), itemResult); + result.push_back(itemResult); + } return; } + // The case where `value` is not an array. result.clear(); + result.reserve(1); T itemResult; - for (auto &itemValue : value) { - fromDynamic(itemValue, itemResult); - result.push_back(itemResult); - } + fromRawValue(rawValue, itemResult); + result.push_back(itemResult); } template -inline T convertRawProp( +T convertRawProp( const RawProps &rawProps, const std::string &name, const T &sourceValue, const T &defaultValue = T()) { - const auto &iterator = rawProps.find(name); - if (iterator == rawProps.end()) { + const auto rawValue = rawProps.at(name); + + if (!rawValue) { return sourceValue; } - const auto &value = iterator->second; - // Special case: `null` always means `the prop was removed, use default // value`. - if (value.isNull()) { + if (!rawValue->hasValue()) { return defaultValue; } T result; - fromDynamic(value, result); + fromRawValue(*rawValue, result); return result; } template -inline static folly::Optional convertRawProp( +static folly::Optional convertRawProp( const RawProps &rawProps, const std::string &name, const folly::Optional &sourceValue, const folly::Optional &defaultValue = {}) { - const auto &iterator = rawProps.find(name); - if (iterator == rawProps.end()) { + const auto rawValue = rawProps.at(name); + + if (!rawValue) { return sourceValue; } - const auto &value = iterator->second; - // Special case: `null` always means `the prop was removed, use default // value`. - if (value.isNull()) { + if (!rawValue->hasValue()) { return defaultValue; } T result; - fromDynamic(value, result); - return result; + fromRawValue(*rawValue, result); + return folly::Optional{result}; } } // namespace react diff --git a/ReactCommon/fabric/core/shadownode/Props.cpp b/ReactCommon/fabric/core/shadownode/Props.cpp index 945f7e666..d56726f7b 100644 --- a/ReactCommon/fabric/core/shadownode/Props.cpp +++ b/ReactCommon/fabric/core/shadownode/Props.cpp @@ -17,7 +17,7 @@ Props::Props(const Props &sourceProps, const RawProps &rawProps) : nativeId(convertRawProp(rawProps, "nativeID", sourceProps.nativeId)) #ifdef ANDROID , - rawProps(rawProps) + rawProps((folly::dynamic)rawProps) #endif {}; diff --git a/ReactCommon/fabric/core/shadownode/Props.h b/ReactCommon/fabric/core/shadownode/Props.h index e2fd66d22..840ef84ad 100644 --- a/ReactCommon/fabric/core/shadownode/Props.h +++ b/ReactCommon/fabric/core/shadownode/Props.h @@ -32,7 +32,7 @@ class Props : public virtual Sealable, public virtual DebugStringConvertible { const std::string nativeId; #ifdef ANDROID - const RawProps rawProps; + const folly::dynamic rawProps = folly::dynamic::object(); #endif }; diff --git a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp index 8dcd11fcc..91c5b5ef8 100644 --- a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp +++ b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp @@ -20,8 +20,7 @@ TEST(ComponentDescriptorTest, createShadowNode) { descriptor->getComponentName().c_str(), TestShadowNode::Name().c_str()); ASSERT_STREQ(descriptor->getComponentName().c_str(), "Test"); - RawProps raw; - raw["nativeID"] = "abc"; + const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); SharedProps props = descriptor->cloneProps(nullptr, raw); SharedShadowNode node = descriptor->createShadowNode( ShadowNodeFragment{.tag = 9, @@ -42,8 +41,7 @@ TEST(ComponentDescriptorTest, cloneShadowNode) { SharedComponentDescriptor descriptor = std::make_shared(nullptr); - RawProps raw; - raw["nativeID"] = "abc"; + const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); SharedProps props = descriptor->cloneProps(nullptr, raw); SharedShadowNode node = descriptor->createShadowNode( ShadowNodeFragment{.tag = 9, @@ -62,8 +60,7 @@ TEST(ComponentDescriptorTest, appendChild) { SharedComponentDescriptor descriptor = std::make_shared(nullptr); - RawProps raw; - raw["nativeID"] = "abc"; + const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); SharedProps props = descriptor->cloneProps(nullptr, raw); SharedShadowNode node1 = descriptor->createShadowNode( ShadowNodeFragment{.tag = 1, diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index cac7546d8..9b5376267 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -16,8 +16,7 @@ using namespace facebook::react; TEST(ShadowNodeTest, handleProps) { - RawProps raw; - raw["nativeID"] = "abc"; + const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); auto props = std::make_shared(Props(), raw); diff --git a/ReactCommon/fabric/core/tests/TestComponent.h b/ReactCommon/fabric/core/tests/TestComponent.h index 8296d6325..8acb11eee 100644 --- a/ReactCommon/fabric/core/tests/TestComponent.h +++ b/ReactCommon/fabric/core/tests/TestComponent.h @@ -13,6 +13,7 @@ #include #include #include +#include #include using namespace facebook::react; @@ -41,7 +42,8 @@ static const char TestComponentName[] = "Test"; class TestProps : public Props { public: using Props::Props; - TestProps() : Props(Props(), {{"nativeID", "testNativeID"}}) {} + TestProps() + : Props(Props(), RawProps(folly::dynamic::object("nativeID", "testNativeID"))) {} }; using SharedTestProps = std::shared_ptr; diff --git a/ReactCommon/fabric/graphics/conversions.h b/ReactCommon/fabric/graphics/conversions.h index 8ff2bd26f..4cd7e456d 100644 --- a/ReactCommon/fabric/graphics/conversions.h +++ b/ReactCommon/fabric/graphics/conversions.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -16,30 +17,30 @@ namespace react { #pragma mark - Color -inline void fromDynamic(const folly::dynamic &value, SharedColor &result) { +inline void fromRawValue(const RawValue &value, SharedColor &result) { float red; float green; float blue; float alpha; - if (value.isNumber()) { - auto argb = value.asInt(); + if (value.hasType()) { + auto argb = (int64_t)value; auto ratio = 256.f; alpha = ((argb >> 24) & 0xFF) / ratio; red = ((argb >> 16) & 0xFF) / ratio; green = ((argb >> 8) & 0xFF) / ratio; blue = (argb & 0xFF) / ratio; - } else if (value.isArray()) { - auto size = value.size(); - assert(size == 3 || size == 4); - red = value[0].asDouble(); - green = value[1].asDouble(); - blue = value[2].asDouble(); - alpha = size == 4 ? value[3].asDouble() : 1.0; + } else if (value.hasType>()) { + auto items = (std::vector)value; + auto length = items.size(); + assert(length == 3 || length == 4); + red = items.at(0); + green = items.at(1); + blue = items.at(2); + alpha = length == 4 ? items.at(3) : 1.0; } else { abort(); } - result = colorFromComponents({red, green, blue, alpha}); } @@ -68,74 +69,84 @@ inline std::string toString(const SharedColor &value) { #pragma mark - Geometry -inline void fromDynamic(const folly::dynamic &value, Point &result) { - if (value.isObject()) { - result = Point{(Float)value["x"].asDouble(), (Float)value["y"].asDouble()}; +inline void fromRawValue(const RawValue &value, Point &result) { + if (value.hasType>()) { + auto map = (std::unordered_map)value; + result = {map.at("x"), map.at("y")}; return; } - if (value.isArray()) { - result = Point{(Float)value[0].asDouble(), (Float)value[1].asDouble()}; + + if (value.hasType>()) { + auto array = (std::vector)value; + assert(array.size() == 2); + result = {array.at(0), array.at(1)}; return; } + abort(); } -inline void fromDynamic(const folly::dynamic &value, Size &result) { - if (value.isObject()) { - result = Size{(Float)value["width"].asDouble(), - (Float)value["height"].asDouble()}; +inline void fromRawValue(const RawValue &value, Size &result) { + if (value.hasType>()) { + auto map = (std::unordered_map)value; + result = {map.at("width"), map.at("height")}; return; } - if (value.isArray()) { - result = Size{(Float)value[0].asDouble(), (Float)value[1].asDouble()}; + + if (value.hasType>()) { + auto array = (std::vector)value; + assert(array.size() == 2); + result = {array.at(0), array.at(1)}; return; } + abort(); } -inline void fromDynamic(const folly::dynamic &value, EdgeInsets &result) { - if (value.isNumber()) { - const Float number = value.asDouble(); - result = EdgeInsets{number, number, number, number}; +inline void fromRawValue(const RawValue &value, EdgeInsets &result) { + if (value.hasType()) { + auto number = (Float)value; + result = {number, number, number, number}; + } + + if (value.hasType>()) { + auto map = (std::unordered_map)value; + result = {map.at("top"), map.at("left"), map.at("bottom"), map.at("right")}; return; } - if (value.isObject()) { - result = EdgeInsets{(Float)value["top"].asDouble(), - (Float)value["left"].asDouble(), - (Float)value["bottom"].asDouble(), - (Float)value["right"].asDouble()}; - return; - } - if (value.isArray()) { - result = EdgeInsets{(Float)value[0].asDouble(), - (Float)value[1].asDouble(), - (Float)value[2].asDouble(), - (Float)value[3].asDouble()}; + + if (value.hasType>()) { + auto array = (std::vector)value; + assert(array.size() == 4); + result = {array.at(0), array.at(1), array.at(2), array.at(3)}; return; } + abort(); } -inline void fromDynamic(const folly::dynamic &value, CornerInsets &result) { - if (value.isNumber()) { - const Float number = value.asDouble(); - result = CornerInsets{number, number, number, number}; +inline void fromRawValue(const RawValue &value, CornerInsets &result) { + if (value.hasType()) { + auto number = (Float)value; + result = {number, number, number, number}; + } + + if (value.hasType>()) { + auto map = (std::unordered_map)value; + result = {map.at("topLeft"), + map.at("topRight"), + map.at("bottomLeft"), + map.at("bottomRight")}; return; } - if (value.isObject()) { - result = CornerInsets{(Float)value["topLeft"].asDouble(), - (Float)value["topRight"].asDouble(), - (Float)value["bottomLeft"].asDouble(), - (Float)value["bottomRight"].asDouble()}; - return; - } - if (value.isArray()) { - result = CornerInsets{(Float)value[0].asDouble(), - (Float)value[1].asDouble(), - (Float)value[2].asDouble(), - (Float)value[3].asDouble()}; + + if (value.hasType>()) { + auto array = (std::vector)value; + assert(array.size() == 4); + result = {array.at(0), array.at(1), array.at(2), array.at(3)}; return; } + abort(); } diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp index e7e33bd81..3af8cf010 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp @@ -112,14 +112,13 @@ SharedShadowNode ComponentDescriptorRegistry::createNode( const SharedEventTarget &eventTarget) const { ComponentName componentName = componentNameByReactViewName(viewName); const SharedComponentDescriptor &componentDescriptor = (*this)[componentName]; - RawProps rawProps = rawPropsFromDynamic(props); SharedShadowNode shadowNode = componentDescriptor->createShadowNode( {.tag = tag, .rootTag = rootTag, .eventEmitter = componentDescriptor->createEventEmitter(std::move(eventTarget), tag), - .props = componentDescriptor->cloneProps(nullptr, rawProps)}); + .props = componentDescriptor->cloneProps(nullptr, RawProps(props))}); return shadowNode; } diff --git a/ReactCommon/fabric/uimanager/UIManager.cpp b/ReactCommon/fabric/uimanager/UIManager.cpp index 49e771700..070da47cc 100644 --- a/ReactCommon/fabric/uimanager/UIManager.cpp +++ b/ReactCommon/fabric/uimanager/UIManager.cpp @@ -33,17 +33,16 @@ SharedShadowNode UIManager::createNode( SharedShadowNode UIManager::cloneNode( const SharedShadowNode &shadowNode, const SharedShadowNodeSharedList &children, - const folly::Optional &rawProps) const { + const RawProps *rawProps) const { auto &componentDescriptor = componentDescriptorRegistry_->at(shadowNode->getComponentHandle()); auto clonedShadowNode = componentDescriptor.cloneShadowNode( *shadowNode, { - .props = rawProps.has_value() - ? componentDescriptor.cloneProps( - shadowNode->getProps(), rawProps.value()) - : ShadowNodeFragment::nullSharedProps(), + .props = rawProps ? componentDescriptor.cloneProps( + shadowNode->getProps(), *rawProps) + : ShadowNodeFragment::nullSharedProps(), .children = children, }); diff --git a/ReactCommon/fabric/uimanager/UIManager.h b/ReactCommon/fabric/uimanager/UIManager.h index 462300265..c39be1336 100644 --- a/ReactCommon/fabric/uimanager/UIManager.h +++ b/ReactCommon/fabric/uimanager/UIManager.h @@ -42,7 +42,7 @@ class UIManager { SharedShadowNode cloneNode( const SharedShadowNode &shadowNode, const SharedShadowNodeSharedList &children = nullptr, - const folly::Optional &rawProps = {}) const; + const RawProps *rawProps = nullptr) const; void appendChild( const SharedShadowNode &parentShadowNode, diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index b8bb17094..126f2bb4d 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -120,7 +120,7 @@ jsi::Value UIManagerBinding::get( tagFromValue(runtime, arguments[0]), componentNameFromValue(runtime, arguments[1]), surfaceIdFromValue(runtime, arguments[2]), - rawPropsFromValue(runtime, arguments[3]), + RawProps(runtime, arguments[3]), eventTargetFromValue(runtime, arguments[4], arguments[0]))); }); } @@ -172,12 +172,13 @@ jsi::Value UIManagerBinding::get( const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { + const auto &rawProps = RawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, uiManager.cloneNode( shadowNodeFromValue(runtime, arguments[0]), nullptr, - rawPropsFromValue(runtime, arguments[1]))); + &rawProps)); }); } @@ -192,12 +193,13 @@ jsi::Value UIManagerBinding::get( const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { + const auto &rawProps = RawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, uiManager.cloneNode( shadowNodeFromValue(runtime, arguments[0]), ShadowNode::emptySharedShadowNodeSharedList(), - rawPropsFromValue(runtime, arguments[1]))); + &rawProps)); }); } @@ -319,7 +321,7 @@ jsi::Value UIManagerBinding::get( size_t count) -> jsi::Value { uiManager.setNativeProps( shadowNodeFromValue(runtime, arguments[0]), - rawPropsFromValue(runtime, arguments[1])); + RawProps(runtime, arguments[1])); return jsi::Value::undefined(); }); diff --git a/ReactCommon/fabric/uimanager/primitives.h b/ReactCommon/fabric/uimanager/primitives.h index 1030900d2..549d541f7 100644 --- a/ReactCommon/fabric/uimanager/primitives.h +++ b/ReactCommon/fabric/uimanager/primitives.h @@ -13,23 +13,6 @@ namespace react { using RuntimeExecutor = std::function &&callback)>; -inline RawProps rawPropsFromDynamic(const folly::dynamic object) noexcept { - RawProps result; - - if (object.isNull()) { - return result; - } - - assert(object.isObject()); - - for (const auto &pair : object.items()) { - assert(pair.first.isString()); - result[pair.first.asString()] = pair.second; - } - - return result; -} - struct EventHandlerWrapper : public EventHandler { EventHandlerWrapper(jsi::Function eventHandler) : callback(std::move(eventHandler)) {} @@ -81,13 +64,6 @@ inline static jsi::Value valueFromShadowNodeList( runtime, std::make_unique(shadowNodeList)); } -inline static RawProps rawPropsFromValue( - jsi::Runtime &runtime, - const jsi::Value &value) { - return rawPropsFromDynamic(folly::dynamic{ - value.isNull() ? nullptr : jsi::dynamicFromValue(runtime, value)}); -} - inline static SharedEventTarget eventTargetFromValue( jsi::Runtime &runtime, const jsi::Value &eventTargetValue, diff --git a/codegen/src/generators/GeneratePropsH.js b/codegen/src/generators/GeneratePropsH.js index deb1bf62f..3c9e0c85e 100644 --- a/codegen/src/generators/GeneratePropsH.js +++ b/codegen/src/generators/GeneratePropsH.js @@ -56,8 +56,8 @@ class ::_CLASSNAME_:: final::_EXTEND_CLASSES_:: { const enumTemplate = ` enum class ::_ENUM_NAME_:: { ::_VALUES_:: }; -static inline void fromDynamic(const folly::dynamic &value, ::_ENUM_NAME_:: &result) { - auto string = value.asString(); +static inline void fromRawValue(const RawValue &value, ::_ENUM_NAME_:: &result) { + auto string = (std::string)value; ::_FROM_CASES_:: abort(); } diff --git a/codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap index d22714db3..543bfd589 100644 --- a/codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -80,8 +80,8 @@ namespace react { enum class EnumPropsNativeComponentAlignment { Top, Center, Bottom }; -static inline void fromDynamic(const folly::dynamic &value, EnumPropsNativeComponentAlignment &result) { - auto string = value.asString(); +static inline void fromRawValue(const RawValue &value, EnumPropsNativeComponentAlignment &result) { + auto string = (std::string)value; if (string == \\"top\\") { result = EnumPropsNativeComponentAlignment::Top; return; } if (string == \\"center\\") { result = EnumPropsNativeComponentAlignment::Center; return; } if (string == \\"bottom\\") { result = EnumPropsNativeComponentAlignment::Bottom; return; }