feat: make Struct tuple-like class (#343)

This commit is contained in:
Stanislav Angelovič
2023-08-02 18:20:06 +02:00
parent f6e597a583
commit 0a2bda9c67
3 changed files with 53 additions and 10 deletions

View File

@ -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 <typename... _ValueTypes>
class Struct
@ -135,6 +139,9 @@ namespace sdbus {
}
};
template <typename... _Elements>
Struct(_Elements...) -> Struct<_Elements...>;
template<typename... _Elements>
constexpr Struct<std::decay_t<_Elements>...>
make_struct(_Elements&&... args)
@ -280,4 +287,14 @@ namespace sdbus {
}
template <size_t _I, typename... _ValueTypes>
struct std::tuple_element<_I, sdbus::Struct<_ValueTypes...>>
: std::tuple_element<_I, std::tuple<_ValueTypes...>>
{};
template <typename... _ValueTypes>
struct std::tuple_size<sdbus::Struct<_ValueTypes...>>
: std::tuple_size<std::tuple<_ValueTypes...>>
{};
#endif /* SDBUS_CXX_TYPES_H_ */

View File

@ -93,7 +93,7 @@ std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vecto
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> TestAdaptor::getStructInStruct()
{
return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}));
return sdbus::Struct{STRING_VALUE, sdbus::Struct{std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}}};
}
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)

View File

@ -67,7 +67,7 @@ TEST(AVariant, CanBeConstructedFromASimpleValue)
TEST(AVariant, CanBeConstructedFromAComplexValue)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
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<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
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<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
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<sdbus::Struct<sdbus::Variant, double>>;
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<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
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<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
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<decltype(value)>(), Eq(value));
}
TEST(AStruct, CreatesStructFromTuple)
TEST(AStruct, CanBeCreatedFromStdTuple)
{
std::tuple<int32_t, std::string> value{1234, "abcd"};
sdbus::Struct<int32_t, std::string> 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<int32_t, std::string> 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<int, std::string, bool>;
static_assert(std::tuple_size_v<StructType> == 3);
static_assert(std::is_same_v<std::tuple_element_t<1, StructType>, 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";