react-native/ReactCommon/fabric/core/propsConversions.h

94 lines
2.3 KiB
C
Raw Normal View History

/**
* 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 <folly/Optional.h>
#include <folly/dynamic.h>
#include <fabric/graphics/Color.h>
#include <fabric/graphics/Geometry.h>
#include <fabric/graphics/conversions.h>
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, std::string &result) { result = value.getString(); }
template <typename T>
inline void fromDynamic(const folly::dynamic &value, std::vector<T> &result) {
if (!value.isArray()) {
T itemResult;
fromDynamic(value, itemResult);
result = {itemResult};
return;
}
result.clear();
T itemResult;
for (auto &itemValue : value) {
fromDynamic(itemValue, itemResult);
result.push_back(itemResult);
}
}
template <typename T>
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
inline 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()) {
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
return sourceValue;
}
const auto &value = iterator->second;
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
// Special case: `null` always means `the prop was removed, use default value`.
if (value.isNull()) {
return defaultValue;
}
T result;
fromDynamic(value, result);
return result;
}
template <typename T>
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
inline static folly::Optional<T> convertRawProp(
const RawProps &rawProps,
const std::string &name,
const folly::Optional<T> &sourceValue,
const folly::Optional<T> &defaultValue = {}
) {
const auto &iterator = rawProps.find(name);
if (iterator == rawProps.end()) {
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
return sourceValue;
}
const auto &value = iterator->second;
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
// Special case: `null` always means `the prop was removed, use default value`.
if (value.isNull()) {
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
return defaultValue;
}
Fabric: `convertRawProp` was extended to accept an optional default value Summary: During transforming raw prop (`rawProps[<prop>]`) to typed props (`MyProps.<prop>`) we can face three different cases: * `rawProps` collection has proper serialized value for the key. In this case, we have to set a new value of the typed prop converting value using `fromDynamic`. * `rawProps` collection does not have value for the key. In this case, we have to copy a value from source prop (`sourceValue`). * `rawProps` collection has `null` value for the key. This is the special case which means that the prop was removed from the particular component instance and we have to reset it to some *default* value (which is *not* the same as `sourceValue`). Now the default value of the `defaultValue` (sic!) argument is a default value of the type of the value (which may be different from logical default value). We didn't handle the last case previously and this caused crashes (and unexpected behavior) because `fromDynamic` often cannot handle `null` value. And yes, all this mean that we also have to update all `convertRawProp` call sites where logical default values are not equal to type-specific default values. This is a potential error-prone place, especially because now we have to specify logical default values in two places (in a prop declaration and in a parameterized constructor). And seems there is no way to avoid that without performance loss (because both of those places are basically constructors). My hope is that codegen (where default values are also defined in JavaScript) will help with it eventually. Reviewed By: fkgozali Differential Revision: D8247652 fbshipit-source-id: 2cbe65f5f5cccd7a0d34aaa19e385aacebfe8cb1
2018-06-09 03:16:22 +00:00
T result;
fromDynamic(value, result);
return result;
}
} // namespace react
} // namespace facebook