Skip to content

Commit

Permalink
Allow parsing lists of compound data types (facebook#49188)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#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
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Feb 5, 2025
1 parent 62ea6e8 commit 1def9fd
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
36 changes: 29 additions & 7 deletions packages/react-native/ReactCommon/react/renderer/css/CSSList.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,45 @@
#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>> {
CSSList<AllowedTypeT, Delim> result;
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()) {
Expand All @@ -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>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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

0 comments on commit 1def9fd

Please sign in to comment.