diff --git a/include/sdbus-c++/TypeTraits.h b/include/sdbus-c++/TypeTraits.h index b75d1e5f..fafe950c 100644 --- a/include/sdbus-c++/TypeTraits.h +++ b/include/sdbus-c++/TypeTraits.h @@ -106,6 +106,9 @@ namespace sdbus { // Tag denoting a call where the reply shouldn't be waited for struct dont_expect_reply_t { explicit dont_expect_reply_t() = default; }; inline constexpr dont_expect_reply_t dont_expect_reply{}; + // Tag denoting that the variant shall embed the other variant as its value, instead of creating a copy + struct embed_variant_t { explicit embed_variant_t() = default; }; + inline constexpr embed_variant_t embed_variant{}; // Helper for static assert template constexpr bool always_false = false; diff --git a/include/sdbus-c++/Types.h b/include/sdbus-c++/Types.h index e3b488d8..b75e3faa 100644 --- a/include/sdbus-c++/Types.h +++ b/include/sdbus-c++/Types.h @@ -67,6 +67,14 @@ namespace sdbus { msg_.seal(); } + Variant(const Variant& value, embed_variant_t) : Variant() + { + msg_.openVariant(); + msg_ << value; + msg_.closeVariant(); + msg_.seal(); + } + template explicit Variant(const as_dictionary<_Struct>& value) : Variant() { diff --git a/tests/integrationtests/DBusPropertiesTests.cpp b/tests/integrationtests/DBusPropertiesTests.cpp index 78cb37d8..59c1b3f3 100644 --- a/tests/integrationtests/DBusPropertiesTests.cpp +++ b/tests/integrationtests/DBusPropertiesTests.cpp @@ -81,3 +81,12 @@ TYPED_TEST(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHa ASSERT_THAT(this->m_adaptor->m_propertySetMsg, NotNull()); ASSERT_THAT(this->m_adaptor->m_propertySetSender, Not(IsEmpty())); } + +TYPED_TEST(SdbusTestObject, WritesAndReadsReadWriteVariantPropertySuccessfully) +{ + sdbus::Variant newActionValue{5678}; + + this->m_proxy->actionVariant(newActionValue); + + ASSERT_THAT(this->m_proxy->actionVariant().template get(), Eq(5678)); +} diff --git a/tests/integrationtests/DBusStandardInterfacesTests.cpp b/tests/integrationtests/DBusStandardInterfacesTests.cpp index d62fe75a..dda623b4 100644 --- a/tests/integrationtests/DBusStandardInterfacesTests.cpp +++ b/tests/integrationtests/DBusStandardInterfacesTests.cpp @@ -141,9 +141,10 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface) { const auto properties = this->m_proxy->GetAll(INTERFACE_NAME); - ASSERT_THAT(properties, SizeIs(3)); + ASSERT_THAT(properties, SizeIs(4)); EXPECT_THAT(properties.at(STATE_PROPERTY).template get(), Eq(DEFAULT_STATE_VALUE)); EXPECT_THAT(properties.at(ACTION_PROPERTY).template get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get().template get(), Eq(DEFAULT_ACTION_VARIANT_VALUE)); EXPECT_THAT(properties.at(BLOCKING_PROPERTY).template get(), Eq(DEFAULT_BLOCKING_VALUE)); } @@ -161,9 +162,10 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfac }); const auto properties = future.get(); - ASSERT_THAT(properties, SizeIs(3)); + ASSERT_THAT(properties, SizeIs(4)); EXPECT_THAT(properties.at(STATE_PROPERTY).get(), Eq(DEFAULT_STATE_VALUE)); EXPECT_THAT(properties.at(ACTION_PROPERTY).get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get().template get(), Eq(DEFAULT_ACTION_VARIANT_VALUE)); EXPECT_THAT(properties.at(BLOCKING_PROPERTY).get(), Eq(DEFAULT_BLOCKING_VALUE)); } @@ -173,9 +175,10 @@ TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfac auto properties = future.get(); - ASSERT_THAT(properties, SizeIs(3)); + ASSERT_THAT(properties, SizeIs(4)); EXPECT_THAT(properties.at(STATE_PROPERTY).template get(), Eq(DEFAULT_STATE_VALUE)); EXPECT_THAT(properties.at(ACTION_PROPERTY).template get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at(ACTION_VARIANT_PROPERTY).template get().template get(), Eq(DEFAULT_ACTION_VARIANT_VALUE)); EXPECT_THAT(properties.at(BLOCKING_PROPERTY).template get(), Eq(DEFAULT_BLOCKING_VALUE)); } @@ -252,17 +255,19 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterface EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1)); #if LIBSYSTEMD_VERSION<=244 // Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case. - EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(4)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_PROPERTY)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY)); #else // Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only // for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal. // So in this specific instance, `action' property is no more added to the list. - EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2)); + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY)); #endif signalReceived = true; }; @@ -288,17 +293,19 @@ TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) #endif #if LIBSYSTEMD_VERSION<=244 // Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case. - EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(4)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_PROPERTY)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY)); #else // Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only // for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal. // So in this specific instance, `action' property is no more added to the list. - EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2)); + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(STATE_PROPERTY)); EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(BLOCKING_PROPERTY)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count(ACTION_VARIANT_PROPERTY)); #endif signalReceived = true; }; diff --git a/tests/integrationtests/Defs.h b/tests/integrationtests/Defs.h index 0bc43f21..97cfcdd6 100644 --- a/tests/integrationtests/Defs.h +++ b/tests/integrationtests/Defs.h @@ -42,6 +42,7 @@ const ObjectPath OBJECT_PATH {"/org/sdbuscpp/integrationtests/ObjectA1"}; const ObjectPath OBJECT_PATH_2{"/org/sdbuscpp/integrationtests/ObjectB1"}; const PropertyName STATE_PROPERTY{"state"}; const PropertyName ACTION_PROPERTY{"action"}; +const PropertyName ACTION_VARIANT_PROPERTY{"actionVariant"}; const PropertyName BLOCKING_PROPERTY{"blocking"}; const std::string DIRECT_CONNECTION_SOCKET_PATH{std::filesystem::temp_directory_path() / "sdbus-cpp-direct-connection-test"}; @@ -58,6 +59,7 @@ const int UNIX_FD_VALUE = 0; const std::string DEFAULT_STATE_VALUE{"default-state-value"}; const uint32_t DEFAULT_ACTION_VALUE{999}; +const std::string DEFAULT_ACTION_VARIANT_VALUE{"ahoj"}; const bool DEFAULT_BLOCKING_VALUE{true}; constexpr const double DOUBLE_VALUE{3.24L}; diff --git a/tests/integrationtests/TestAdaptor.cpp b/tests/integrationtests/TestAdaptor.cpp index aa36f08a..21f5330c 100644 --- a/tests/integrationtests/TestAdaptor.cpp +++ b/tests/integrationtests/TestAdaptor.cpp @@ -266,6 +266,16 @@ void TestAdaptor::action(const uint32_t& value) m_action = value; } +sdbus::Variant TestAdaptor::actionVariant() +{ + return m_actionVariant; +} + +void TestAdaptor::actionVariant(const sdbus::Variant& value) +{ + m_actionVariant = value; +} + bool TestAdaptor::blocking() { return m_blocking; diff --git a/tests/integrationtests/TestAdaptor.h b/tests/integrationtests/TestAdaptor.h index 27dd4575..c6463766 100644 --- a/tests/integrationtests/TestAdaptor.h +++ b/tests/integrationtests/TestAdaptor.h @@ -89,6 +89,8 @@ class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integr uint32_t action() override; void action(const uint32_t& value) override; + sdbus::Variant actionVariant() override; + void actionVariant(const sdbus::Variant& value) override; bool blocking() override; void blocking(const bool& value) override; std::string state() override; @@ -101,6 +103,7 @@ class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integr const std::string m_state{DEFAULT_STATE_VALUE}; uint32_t m_action{DEFAULT_ACTION_VALUE}; bool m_blocking{DEFAULT_BLOCKING_VALUE}; + sdbus::Variant m_actionVariant{"ahoj"}; public: // for tests // For dont-expect-reply method call verifications @@ -152,6 +155,8 @@ class DummyTestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::i uint32_t action() override { return {}; } void action(const uint32_t&) override {} + sdbus::Variant actionVariant() override { return {}; } + void actionVariant(const sdbus::Variant&) override {} bool blocking() override { return {}; } void blocking(const bool&) override {} std::string state() override { return {}; } diff --git a/tests/integrationtests/integrationtests-adaptor.h b/tests/integrationtests/integrationtests-adaptor.h index bece2020..6c86001f 100644 --- a/tests/integrationtests/integrationtests-adaptor.h +++ b/tests/integrationtests/integrationtests-adaptor.h @@ -63,6 +63,7 @@ class integrationtests_adaptor , sdbus::registerSignal("signalWithMap").withParameters>("aMap") , sdbus::registerSignal("signalWithVariant").withParameters("aVariant") , sdbus::registerProperty("action").withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL) + , sdbus::registerProperty("actionVariant").withGetter([this](){ return this->actionVariant(); }).withSetter([this](const sdbus::Variant& value){ this->actionVariant(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL) , sdbus::registerProperty("blocking").withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); }) , sdbus::registerProperty("state").withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE) ).forInterface(INTERFACE_NAME); @@ -113,7 +114,9 @@ class integrationtests_adaptor private: virtual uint32_t action() = 0; + virtual sdbus::Variant actionVariant() = 0; virtual void action(const uint32_t& value) = 0; + virtual void actionVariant(const sdbus::Variant& value) = 0; virtual bool blocking() = 0; virtual void blocking(const bool& value) = 0; virtual std::string state() = 0; diff --git a/tests/integrationtests/integrationtests-proxy.h b/tests/integrationtests/integrationtests-proxy.h index 94be8450..64d93c45 100644 --- a/tests/integrationtests/integrationtests-proxy.h +++ b/tests/integrationtests/integrationtests-proxy.h @@ -225,6 +225,16 @@ class integrationtests_proxy m_proxy.setProperty("action").onInterface(INTERFACE_NAME).toValue(value); } + sdbus::Variant actionVariant() + { + return m_proxy.getProperty("actionVariant").onInterface(INTERFACE_NAME).get(); + } + + void actionVariant(const sdbus::Variant& value) + { + m_proxy.setProperty("actionVariant").onInterface(INTERFACE_NAME).toValue({value, sdbus::embed_variant}); + } + bool blocking() { return m_proxy.getProperty("blocking").onInterface(INTERFACE_NAME).get(); diff --git a/tools/xml2cpp-codegen/ProxyGenerator.cpp b/tools/xml2cpp-codegen/ProxyGenerator.cpp index 0e107485..cbd17aaf 100644 --- a/tools/xml2cpp-codegen/ProxyGenerator.cpp +++ b/tools/xml2cpp-codegen/ProxyGenerator.cpp @@ -375,6 +375,9 @@ std::tuple ProxyGenerator::processProperties(const Nod if (propertyAccess == "readwrite" || propertyAccess == "write") { + if (propertySignature == "v") + propertyArg = "{" + propertyArg + ", sdbus::embed_variant}"; + const std::string realRetType = (asyncSet ? (futureSet ? "std::future" : "sdbus::PendingAsyncCall") : "void"); propertySS << tab << realRetType << " " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl