Allow parsing lists of compound data types (#49188)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49188

This allows creating lists of a compound data type, storing each element as a variant of the possible types, instead of as the specified type.

Changelog: [Internal]

Reviewed By: lenaic

Differential Revision: D69142157

fbshipit-source-id: d742d81a6517b24f24827727cd777550f2ad274f
This commit is contained in:
Nick Gerleman
2025-02-04 21:51:21 -08:00
committed by Facebook GitHub Bot
parent 62ea6e891c
commit 1def9fdbc9
3 changed files with 54 additions and 8 deletions
@@ -21,13 +21,17 @@ struct CSSCompoundDataTypeMarker {};
template <CSSDataType... AllowedTypesT>
struct CSSCompoundDataType : public detail::CSSCompoundDataTypeMarker {};
template <typename T>
concept CSSValidCompoundDataType =
std::is_base_of_v<detail::CSSCompoundDataTypeMarker, T>;
/**
* A concrete data type, or a compound data type which represents multiple other
* data types.
*/
template <typename T>
concept CSSMaybeCompoundDataType =
CSSDataType<T> || std::is_base_of_v<detail::CSSCompoundDataTypeMarker, T>;
CSSDataType<T> || CSSValidCompoundDataType<T>;
namespace detail {
@@ -8,17 +8,26 @@
#pragma once
#include <optional>
#include <type_traits>
#include <variant>
#include <react/renderer/css/CSSCompoundDataType.h>
#include <react/renderer/css/CSSDataType.h>
#include <react/renderer/css/CSSValueParser.h>
namespace facebook::react {
template <CSSDataType AllowedTypeT, CSSDelimiter Delim>
struct CSSList : public std::vector<AllowedTypeT> {};
template <CSSMaybeCompoundDataType T, CSSDelimiter Delim>
struct CSSList;
template <CSSDataType AllowedTypeT, CSSDelimiter Delim>
struct CSSList<AllowedTypeT, Delim> : public std::vector<AllowedTypeT> {};
template <CSSValidCompoundDataType AllowedTypesT, CSSDelimiter Delim>
struct CSSList<AllowedTypesT, Delim>
: public std::vector<CSSVariantWithTypes<AllowedTypesT>> {};
template <CSSMaybeCompoundDataType AllowedTypeT, CSSDelimiter Delim>
struct CSSDataTypeParser<CSSList<AllowedTypeT, Delim>> {
static inline auto consume(CSSSyntaxParser& parser)
-> std::optional<CSSList<AllowedTypeT, Delim>> {
@@ -26,7 +35,18 @@ struct CSSDataTypeParser<CSSList<AllowedTypeT, Delim>> {
for (auto nextValue = parseNextCSSValue<AllowedTypeT>(parser);
!std::holds_alternative<std::monostate>(nextValue);
nextValue = parseNextCSSValue<AllowedTypeT>(parser, Delim)) {
result.push_back(std::move(std::get<AllowedTypeT>(nextValue)));
// Copy from the variant of possible values to the element (either the
// concrete type, or a variant of compound types which exlcudes the
// possibility of std::monostate for parse error)
std::visit(
[&](auto&& v) {
if constexpr (!std::is_same_v<
std::remove_cvref_t<decltype(v)>,
std::monostate>) {
result.push_back(std::forward<decltype(v)>(v));
}
},
nextValue);
}
if (result.empty()) {
@@ -38,17 +58,19 @@ struct CSSDataTypeParser<CSSList<AllowedTypeT, Delim>> {
};
/**
* Represents a comma-separated repetition of a given single type.
* Represents a comma-separated repetition of a single type, or compound type
* (represented as a variant of possible types).
* https://www.w3.org/TR/css-values-4/#mult-comma
*/
template <CSSDataType AllowedTypeT>
template <CSSMaybeCompoundDataType AllowedTypeT>
using CSSCommaSeparatedList = CSSList<AllowedTypeT, CSSDelimiter::Comma>;
/**
* Represents a whitespace-separated repetition of a given single type.
* Represents a whitespace-separated repetition of a single type, or compound
* type (represented as a variant of possible types).
* https://www.w3.org/TR/css-values-4/#component-combinators
*/
template <CSSDataType AllowedTypeT>
template <CSSMaybeCompoundDataType AllowedTypeT>
using CSSWhitespaceSeparatedList =
CSSList<AllowedTypeT, CSSDelimiter::Whitespace>;
@@ -6,6 +6,8 @@
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSCompoundDataType.h>
#include <react/renderer/css/CSSLength.h>
#include <react/renderer/css/CSSList.h>
#include <react/renderer/css/CSSNumber.h>
#include <react/renderer/css/CSSValueParser.h>
@@ -130,4 +132,22 @@ TEST(CSSList, extra_commas) {
EXPECT_TRUE(std::holds_alternative<std::monostate>(suffixCommaValue));
}
TEST(CSSList, compound_data_type) {
using NumberLengthList =
CSSCommaSeparatedList<CSSCompoundDataType<CSSNumber, CSSLength>>;
auto compoundType = parseCSSProperty<NumberLengthList>("10px,20");
EXPECT_TRUE(std::holds_alternative<NumberLengthList>(compoundType));
auto& list = std::get<NumberLengthList>(compoundType);
EXPECT_EQ(list.size(), 2);
EXPECT_TRUE(std::holds_alternative<CSSLength>(list[0]));
EXPECT_EQ(std::get<CSSLength>(list[0]).value, 10);
EXPECT_EQ(std::get<CSSLength>(list[0]).unit, CSSLengthUnit::Px);
EXPECT_TRUE(std::holds_alternative<CSSNumber>(list[1]));
EXPECT_EQ(std::get<CSSNumber>(list[1]).value, 20);
}
} // namespace facebook::react