[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_