diff --git a/libtransmission/serializer.h b/libtransmission/serializer.h index 72f518461..89499afb7 100644 --- a/libtransmission/serializer.h +++ b/libtransmission/serializer.h @@ -383,6 +383,20 @@ bool set_if_changed(T& tgt, Fields const& fields, Key const key, Value val) return key_found && changed; } +/** + * Check whether a key exists in a `fields` tuple. + */ +template +[[nodiscard]] bool constexpr contains(Fields const& fields, Key const key) +{ + if constexpr (std::tuple_size_v> == 0) + { + return false; + } + + return std::apply([key](auto const&... field) { return ((field.key == key) || ...); }, fields); +} + /** * Get a field's value. * diff --git a/tests/libtransmission/serializer-tests.cc b/tests/libtransmission/serializer-tests.cc index 4c163bd90..2697d5f3b 100644 --- a/tests/libtransmission/serializer-tests.cc +++ b/tests/libtransmission/serializer-tests.cc @@ -297,6 +297,7 @@ TEST_F(SerializerTest, optionalRejectsWrongType) // --- +using libtransmission::serializer::contains; using libtransmission::serializer::Field; using libtransmission::serializer::get_value; using libtransmission::serializer::load; @@ -475,6 +476,24 @@ TEST_F(SerializerTest, setFloatScaled) EXPECT_DOUBLE_EQ(thing.d, val); } +TEST_F(SerializerTest, containsMissingKey) +{ + EXPECT_FALSE(contains(Thing::Fields, TR_KEY_address)); +} + +TEST_F(SerializerTest, containsOk) +{ + EXPECT_TRUE(contains(Thing::Fields, TR_KEY_port)); + EXPECT_TRUE(contains(Thing::Fields, TR_KEY_alt_speed_up)); + EXPECT_TRUE(contains(Thing::Fields, TR_KEY_name)); +} + +TEST_F(SerializerTest, containsEmptyFields) +{ + static constexpr auto Empty = std::tuple{}; + EXPECT_FALSE(contains(Empty, TR_KEY_name)); +} + TEST_F(SerializerTest, getMissingKey) { auto thing = Thing{};