diff --git a/include/sdbus-c++/Types.h b/include/sdbus-c++/Types.h index c9c10e8f..0e2a811b 100644 --- a/include/sdbus-c++/Types.h +++ b/include/sdbus-c++/Types.h @@ -104,6 +104,10 @@ namespace sdbus { * * Representation of struct D-Bus type * + * Struct implements tuple protocol, i.e. it's a tuple-like class. + * It can be used with std::get<>(), std::tuple_element, + * std::tuple_size and in structured bindings. + * ***********************************************/ template class Struct @@ -135,6 +139,9 @@ namespace sdbus { } }; + template + Struct(_Elements...) -> Struct<_Elements...>; + template constexpr Struct...> make_struct(_Elements&&... args) @@ -280,4 +287,14 @@ namespace sdbus { } +template +struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>> + : std::tuple_element<_I, std::tuple<_ValueTypes...>> +{}; + +template +struct std::tuple_size> + : std::tuple_size> +{}; + #endif /* SDBUS_CXX_TYPES_H_ */ diff --git a/tests/integrationtests/TestAdaptor.cpp b/tests/integrationtests/TestAdaptor.cpp index bc966dae..cfbe83f8 100644 --- a/tests/integrationtests/TestAdaptor.cpp +++ b/tests/integrationtests/TestAdaptor.cpp @@ -93,7 +93,7 @@ std::map TestAdaptor::getMapOfVariants(const std::vecto sdbus::Struct>> TestAdaptor::getStructInStruct() { - return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map{{INT32_VALUE, INT32_VALUE}})); + return sdbus::Struct{STRING_VALUE, sdbus::Struct{std::map{{INT32_VALUE, INT32_VALUE}}}}; } int32_t TestAdaptor::sumStructItems(const sdbus::Struct& a, const sdbus::Struct& b) diff --git a/tests/unittests/Types_test.cpp b/tests/unittests/Types_test.cpp index ed1eaa3b..2142d464 100644 --- a/tests/unittests/Types_test.cpp +++ b/tests/unittests/Types_test.cpp @@ -67,7 +67,7 @@ TEST(AVariant, CanBeConstructedFromASimpleValue) TEST(AVariant, CanBeConstructedFromAComplexValue) { using ComplexType = std::map>>; - ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} }; + ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} }; ASSERT_NO_THROW(sdbus::Variant{value}); } @@ -103,7 +103,7 @@ TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked) TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked) { using ComplexType = std::map>>; - ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} }; + ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} }; sdbus::Variant variant(value); @@ -123,7 +123,7 @@ TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes) TEST(AVariant, ReturnsTrueWhenAskedIfItContainsTheTypeItReallyContains) { using ComplexType = std::map>>; - ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} }; + ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} }; sdbus::Variant variant(value); @@ -143,8 +143,8 @@ TEST(AVariant, CanContainOtherEmbeddedVariants) { using TypeWithVariants = std::vector>; TypeWithVariants value; - value.emplace_back(sdbus::make_struct(sdbus::Variant("a string"), ANY_DOUBLE)); - value.emplace_back(sdbus::make_struct(sdbus::Variant(ANY_UINT64), ANY_DOUBLE)); + value.push_back({sdbus::Variant("a string"), ANY_DOUBLE}); + value.push_back({sdbus::Variant(ANY_UINT64), ANY_DOUBLE}); sdbus::Variant variant(value); @@ -172,7 +172,7 @@ TEST(AnEmptyVariant, ThrowsWhenBeingSerializedToAMessage) TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully) { using ComplexType = std::map>>; - ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} }; + ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} }; sdbus::Variant variant(value); auto msg = sdbus::createPlainMessage(); @@ -187,7 +187,7 @@ TEST(ANonEmptyVariant, SerializesToAndDeserializesFromAMessageSuccessfully) TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully) { using ComplexType = std::map>>; - ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{sdbus::make_struct("hello"s, ANY_DOUBLE), sdbus::make_struct("world"s, ANY_DOUBLE)}} }; + ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} }; sdbus::Variant variant(value); auto variantCopy1{variant}; auto variantCopy2 = variant; @@ -207,15 +207,41 @@ TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully) ASSERT_THAT(receivedVariant3.get(), Eq(value)); } -TEST(AStruct, CreatesStructFromTuple) +TEST(AStruct, CanBeCreatedFromStdTuple) { std::tuple value{1234, "abcd"}; - sdbus::Struct valueStruct{value}; + sdbus::Struct valueStruct{value}; + + ASSERT_THAT(valueStruct.get<0>(), Eq(std::get<0>(value))); + ASSERT_THAT(valueStruct.get<1>(), Eq(std::get<1>(value))); +} + +TEST(AStruct, CanProvideItsDataThroughStdGet) +{ + std::tuple value{1234, "abcd"}; + sdbus::Struct valueStruct{value}; ASSERT_THAT(std::get<0>(valueStruct), Eq(std::get<0>(value))); ASSERT_THAT(std::get<1>(valueStruct), Eq(std::get<1>(value))); } +TEST(AStruct, CanBeUsedLikeStdTupleType) +{ + using StructType = sdbus::Struct; + + static_assert(std::tuple_size_v == 3); + static_assert(std::is_same_v, std::string>); +} + +TEST(AStruct, CanBeUsedInStructuredBinding) +{ + sdbus::Struct valueStruct(1234, "abcd", true); + + auto [first, second, third] = valueStruct; + + ASSERT_THAT(std::tie(first, second, third), Eq(std::tuple{1234, "abcd", true})); +} + TEST(AnObjectPath, CanBeConstructedFromCString) { const char* aPath = "/some/path";