[tint][utils] Add TINT_REFLECT_ENUM_RANGE Use the reflected range by the deserializer to know the valid range. Change-Id: I0f9377b0a2f1dc1b122110c30ddf263f7d8f2fad Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/167980 Reviewed-by: dan sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/api/options/pixel_local.h b/src/tint/api/options/pixel_local.h index d8f22ce..61e177b 100644 --- a/src/tint/api/options/pixel_local.h +++ b/src/tint/api/options/pixel_local.h
@@ -50,12 +50,15 @@ std::unordered_map<uint32_t, TexelFormat> attachment_formats; /// The bind group index of all pixel local storage attachments - uint32_t pixel_local_group_index; + uint32_t pixel_local_group_index = 0; /// Reflect the fields of this class so that it can be used by tint::ForeachField() TINT_REFLECT(attachments, attachment_formats, pixel_local_group_index); }; +/// Reflect valid value ranges for the PixelLocalOptions::TexelFormat enum. +TINT_REFLECT_ENUM_RANGE(PixelLocalOptions::TexelFormat, kR32Sint, kR32Float); + } // namespace tint #endif // SRC_TINT_API_OPTIONS_PIXEL_LOCAL_H_
diff --git a/src/tint/utils/bytes/decoder.h b/src/tint/utils/bytes/decoder.h index d759ba8..9fd4e7d 100644 --- a/src/tint/utils/bytes/decoder.h +++ b/src/tint/utils/bytes/decoder.h
@@ -174,6 +174,29 @@ } }; +/// Decoder specialization for enum types that have a range defined with TINT_REFLECT_ENUM_RANGE +template <typename T> +struct Decoder<T, std::void_t<decltype(tint::EnumRange<T>::kMax)>> { + /// Decode decodes the enum type from @p reader. + /// @param reader the reader to decode from + /// @param endianness the endianness of the enum + /// @returns the decoded enum type, or an error if the stream is too short. + static Result<T> Decode(Reader& reader, Endianness endianness = Endianness::kLittle) { + using Range = tint::EnumRange<T>; + using U = std::underlying_type_t<T>; + auto value = reader.Int<U>(endianness); + if (value != Success) { + return value.Failure(); + } + static constexpr U kMin = static_cast<U>(Range::kMin); + static constexpr U kMax = static_cast<U>(Range::kMax); + if (value.Get() < kMin || value.Get() > kMax) { + return Failure{"value " + std::to_string(value.Get()) + " out of range for enum"}; + } + return static_cast<T>(value.Get()); + } +}; + } // namespace tint::bytes #endif // SRC_TINT_UTILS_BYTES_DECODER_H_
diff --git a/src/tint/utils/bytes/decoder_test.cc b/src/tint/utils/bytes/decoder_test.cc index d9169dc..2568182 100644 --- a/src/tint/utils/bytes/decoder_test.cc +++ b/src/tint/utils/bytes/decoder_test.cc
@@ -34,9 +34,19 @@ #include "gmock/gmock.h" +namespace tint { +namespace { +/// An enum used for decoder tests below. +enum class TestEnum : uint8_t { A = 2, B = 3, C = 4 }; +} // namespace + +/// Reflect valid value ranges for the TestEnum enum. +TINT_REFLECT_ENUM_RANGE(TestEnum, A, C); + +} // namespace tint + namespace tint::bytes { namespace { - template <typename... ARGS> auto Data(ARGS&&... args) { return std::array{std::byte{static_cast<uint8_t>(args)}...}; @@ -117,6 +127,15 @@ EXPECT_NE(Decode<S>(reader), Success); } +TEST(BytesDecoderTest, ReflectedEnum) { + auto data = Data(0x03, 0x01, 0x05); + auto reader = BufferReader{Slice{data}}; + auto got = Decode<TestEnum>(reader); + EXPECT_EQ(got, TestEnum::B); + EXPECT_NE(Decode<S>(reader), Success); // Out of range + EXPECT_NE(Decode<S>(reader), Success); // Out of range +} + TEST(BytesDecoderTest, UnorderedMap) { using M = std::unordered_map<uint8_t, uint16_t>; auto data = Data(0x00, 0x10, 0x02, 0x20, //
diff --git a/src/tint/utils/reflection/reflection.h b/src/tint/utils/reflection/reflection.h index bfb2ffa..d674db1 100644 --- a/src/tint/utils/reflection/reflection.h +++ b/src/tint/utils/reflection/reflection.h
@@ -76,6 +76,20 @@ } \ } +/// A template that can be specialized to reflect the valid range of an enum +/// Use TINT_REFLECT_ENUM_RANGE to specialize this class +template <typename T> +struct EnumRange; + +/// Declares a specialization of EnumRange for the enum ENUM with the lowest enum value MIN and +/// largest enum value MAX. Must only be used in the `tint` namespace. +#define TINT_REFLECT_ENUM_RANGE(ENUM, MIN, MAX) \ + template <> \ + struct EnumRange<ENUM> { \ + static constexpr ENUM kMin = ENUM::MIN; \ + static constexpr ENUM kMax = ENUM::MAX; \ + } + } // namespace tint #endif // SRC_TINT_UTILS_REFLECTION_REFLECTION_H_