From eade6a0e44b88c7139ce18aa19cfe0dd8dce6ec2 Mon Sep 17 00:00:00 2001 From: sangelovic Date: Mon, 27 Jan 2020 07:57:38 +0100 Subject: [PATCH] Add support for method and signal parameter names in introspection --- include/sdbus-c++/ConvenienceApiClasses.h | 16 +++ include/sdbus-c++/ConvenienceApiClasses.inl | 64 ++++++++- include/sdbus-c++/IObject.h | 68 ++++++++-- src/Object.cpp | 123 ++++++++++++------ src/Object.h | 65 +++++---- src/VTableUtils.c | 28 ++++ src/VTableUtils.h | 2 + tests/integrationtests/adaptor-glue.h | 26 ++-- tests/perftests/perftests-adaptor.h | 6 +- .../stresstests/celsius-thermometer-adaptor.h | 2 +- tests/stresstests/concatenator-adaptor.h | 4 +- .../fahrenheit-thermometer-adaptor.h | 6 +- tools/xml2cpp-codegen/AdaptorGenerator.cpp | 13 +- tools/xml2cpp-codegen/BaseGenerator.cpp | 8 +- tools/xml2cpp-codegen/BaseGenerator.h | 2 +- tools/xml2cpp-codegen/ProxyGenerator.cpp | 6 +- 16 files changed, 329 insertions(+), 110 deletions(-) diff --git a/include/sdbus-c++/ConvenienceApiClasses.h b/include/sdbus-c++/ConvenienceApiClasses.h index 225e00e..53c3663 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.h +++ b/include/sdbus-c++/ConvenienceApiClasses.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,9 @@ namespace sdbus { namespace sdbus { + template + inline constexpr bool are_strings_v = std::conjunction...>::value; + class MethodRegistrator { public: @@ -57,6 +61,12 @@ namespace sdbus { std::enable_if_t, MethodRegistrator&> implementedAs(_Function&& callback); template std::enable_if_t, MethodRegistrator&> implementedAs(_Function&& callback); + MethodRegistrator& withInputParamNames(std::vector paramNames); + template + std::enable_if_t, MethodRegistrator&> withInputParamNames(_String... paramNames); + MethodRegistrator& withOutputParamNames(std::vector paramNames); + template + std::enable_if_t, MethodRegistrator&> withOutputParamNames(_String... paramNames); MethodRegistrator& markAsDeprecated(); MethodRegistrator& markAsPrivileged(); MethodRegistrator& withNoReply(); @@ -66,7 +76,9 @@ namespace sdbus { const std::string& methodName_; std::string interfaceName_; std::string inputSignature_; + std::vector inputParamNames_; std::string outputSignature_; + std::vector outputParamNames_; method_callback methodCallback_; Flags flags_; int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed @@ -81,6 +93,9 @@ namespace sdbus { SignalRegistrator& onInterface(std::string interfaceName); template SignalRegistrator& withParameters(); + template SignalRegistrator& withParameters(std::vector paramNames); + template + std::enable_if_t, SignalRegistrator&> withParameters(_String... paramNames); SignalRegistrator& markAsDeprecated(); private: @@ -88,6 +103,7 @@ namespace sdbus { const std::string& signalName_; std::string interfaceName_; std::string signalSignature_; + std::vector paramNames_; Flags flags_; int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed }; diff --git a/include/sdbus-c++/ConvenienceApiClasses.inl b/include/sdbus-c++/ConvenienceApiClasses.inl index a0c5688..f4a3b40 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.inl +++ b/include/sdbus-c++/ConvenienceApiClasses.inl @@ -70,7 +70,14 @@ namespace sdbus { // Therefore, we can allow registerMethod() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(methodCallback_), flags_); + object_.registerMethod( interfaceName_ + , std::move(methodName_) + , std::move(inputSignature_) + , std::move(inputParamNames_) + , std::move(outputSignature_) + , std::move(outputParamNames_) + , std::move(methodCallback_) + , std::move(flags_)); } inline MethodRegistrator& MethodRegistrator::onInterface(std::string interfaceName) @@ -81,7 +88,8 @@ namespace sdbus { } template - inline std::enable_if_t, MethodRegistrator&> MethodRegistrator::implementedAs(_Function&& callback) + inline std::enable_if_t, MethodRegistrator&> + MethodRegistrator::implementedAs(_Function&& callback) { inputSignature_ = signature_of_function_input_arguments<_Function>::str(); outputSignature_ = signature_of_function_output_arguments<_Function>::str(); @@ -110,7 +118,8 @@ namespace sdbus { } template - inline std::enable_if_t, MethodRegistrator&> MethodRegistrator::implementedAs(_Function&& callback) + inline std::enable_if_t, MethodRegistrator&> + MethodRegistrator::implementedAs(_Function&& callback) { inputSignature_ = signature_of_function_input_arguments<_Function>::str(); outputSignature_ = signature_of_function_output_arguments<_Function>::str(); @@ -130,6 +139,32 @@ namespace sdbus { return *this; } + inline MethodRegistrator& MethodRegistrator::withInputParamNames(std::vector paramNames) + { + inputParamNames_ = std::move(paramNames); + + return *this; + } + + template + inline std::enable_if_t, MethodRegistrator&> MethodRegistrator::withInputParamNames(_String... paramNames) + { + return withInputParamNames({paramNames...}); + } + + inline MethodRegistrator& MethodRegistrator::withOutputParamNames(std::vector paramNames) + { + outputParamNames_ = std::move(paramNames); + + return *this; + } + + template + inline std::enable_if_t, MethodRegistrator&> MethodRegistrator::withOutputParamNames(_String... paramNames) + { + return withOutputParamNames({paramNames...}); + } + inline MethodRegistrator& MethodRegistrator::markAsDeprecated() { flags_.set(Flags::DEPRECATED); @@ -179,7 +214,11 @@ namespace sdbus { // Therefore, we can allow registerSignal() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - object_.registerSignal(interfaceName_, signalName_, signalSignature_, flags_); + object_.registerSignal( interfaceName_ + , std::move(signalName_) + , std::move(signalSignature_) + , std::move(paramNames_) + , std::move(flags_) ); } inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName) @@ -197,6 +236,23 @@ namespace sdbus { return *this; } + template + inline SignalRegistrator& SignalRegistrator::withParameters(std::vector paramNames) + { + paramNames_ = std::move(paramNames); + + return withParameters<_Args...>(); + } + + template + inline std::enable_if_t, SignalRegistrator&> + SignalRegistrator::withParameters(_String... paramNames) + { + static_assert(sizeof...(_Args) == sizeof...(_String), "Numbers of signal parameters and their names don't match"); + + return withParameters<_Args...>({paramNames...}); + } + inline SignalRegistrator& SignalRegistrator::markAsDeprecated() { flags_.set(Flags::DEPRECATED); diff --git a/include/sdbus-c++/IObject.h b/include/sdbus-c++/IObject.h index ab31997..78d6b9e 100644 --- a/include/sdbus-c++/IObject.h +++ b/include/sdbus-c++/IObject.h @@ -74,9 +74,37 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual void registerMethod( const std::string& interfaceName - , const std::string& methodName - , const std::string& inputSignature - , const std::string& outputSignature + , std::string methodName + , std::string inputSignature + , std::string outputSignature + , method_callback methodCallback + , Flags flags = {} ) = 0; + + /*! + * @brief Registers method that the object will provide on D-Bus + * + * @param[in] interfaceName Name of an interface that the method will belong to + * @param[in] methodName Name of the method + * @param[in] inputSignature D-Bus signature of method input parameters + * @param[in] inputNames Names of input parameters + * @param[in] outputSignature D-Bus signature of method output parameters + * @param[in] outputNames Names of output parameters + * @param[in] methodCallback Callback that implements the body of the method + * @param[in] flags D-Bus method flags (privileged, deprecated, or no reply) + * + * Provided names of input and output parameters will be included in the introspection + * description (given that at least version 242 of underlying libsystemd library is + * used; otherwise, names of parameters are ignored). This usually helps better describe + * the API to the introspector. + * + * @throws sdbus::Error in case of failure + */ + virtual void registerMethod( const std::string& interfaceName + , std::string methodName + , std::string inputSignature + , const std::vector& inputNames + , std::string outputSignature + , const std::vector& outputNames , method_callback methodCallback , Flags flags = {} ) = 0; @@ -91,8 +119,30 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual void registerSignal( const std::string& interfaceName - , const std::string& signalName - , const std::string& signature + , std::string signalName + , std::string signature + , Flags flags = {} ) = 0; + + /*! + * @brief Registers signal that the object will emit on D-Bus + * + * @param[in] interfaceName Name of an interface that the signal will fall under + * @param[in] signalName Name of the signal + * @param[in] signature D-Bus signature of signal parameters + * @param[in] paramNames Names of parameters of the signal + * @param[in] flags D-Bus signal flags (deprecated) + * + * Provided names of signal output parameters will be included in the introspection + * description (given that at least version 242 of underlying libsystemd library is + * used; otherwise, names of parameters are ignored). This usually helps better describe + * the API to the introspector. + * + * @throws sdbus::Error in case of failure + */ + virtual void registerSignal( const std::string& interfaceName + , std::string signalName + , std::string signature + , const std::vector& paramNames , Flags flags = {} ) = 0; /*! @@ -107,8 +157,8 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual void registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , Flags flags = {} ) = 0; @@ -125,8 +175,8 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual void registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , property_set_callback setCallback , Flags flags = {} ) = 0; diff --git a/src/Object.cpp b/src/Object.cpp index be971c9..b1a4bc8 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -45,51 +45,83 @@ Object::Object(sdbus::internal::IConnection& connection, std::string objectPath) } void Object::registerMethod( const std::string& interfaceName - , const std::string& methodName - , const std::string& inputSignature - , const std::string& outputSignature + , std::string methodName + , std::string inputSignature + , std::string outputSignature + , method_callback methodCallback + , Flags flags ) +{ + registerMethod( interfaceName + , std::move(methodName) + , std::move(inputSignature) + , {} + , std::move(outputSignature) + , {} + , std::move(methodCallback) + , std::move(flags) ); +} + +void Object::registerMethod( const std::string& interfaceName + , std::string methodName + , std::string inputSignature + , const std::vector& inputNames + , std::string outputSignature + , const std::vector& outputNames , method_callback methodCallback , Flags flags ) { SDBUS_THROW_ERROR_IF(!methodCallback, "Invalid method callback provided", EINVAL); auto& interface = interfaces_[interfaceName]; - InterfaceData::MethodData methodData{inputSignature, outputSignature, std::move(methodCallback), flags}; - auto inserted = interface.methods_.emplace(methodName, std::move(methodData)).second; + InterfaceData::MethodData methodData{ std::move(inputSignature) + , std::move(outputSignature) + , paramNamesToString(inputNames) + paramNamesToString(outputNames) + , std::move(methodCallback) + , std::move(flags) }; + auto inserted = interface.methods.emplace(std::move(methodName), std::move(methodData)).second; SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL); } void Object::registerSignal( const std::string& interfaceName - , const std::string& signalName - , const std::string& signature + , std::string signalName + , std::string signature + , Flags flags ) +{ + registerSignal(interfaceName, std::move(signalName), std::move(signature), {}, std::move(flags)); +} + +void Object::registerSignal( const std::string& interfaceName + , std::string signalName + , std::string signature + , const std::vector& paramNames , Flags flags ) { auto& interface = interfaces_[interfaceName]; - InterfaceData::SignalData signalData{signature, flags}; - auto inserted = interface.signals_.emplace(signalName, std::move(signalData)).second; + InterfaceData::SignalData signalData{std::move(signature), paramNamesToString(paramNames), std::move(flags)}; + auto inserted = interface.signals.emplace(std::move(signalName), std::move(signalData)).second; SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal: signal already exists", EINVAL); } void Object::registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , Flags flags ) { registerProperty( interfaceName - , propertyName - , signature - , getCallback - , property_set_callback{} - , flags ); + , std::move(propertyName) + , std::move(signature) + , std::move(getCallback) + , {} + , std::move(flags) ); } void Object::registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , property_set_callback setCallback , Flags flags ) @@ -98,8 +130,11 @@ void Object::registerProperty( const std::string& interfaceName auto& interface = interfaces_[interfaceName]; - InterfaceData::PropertyData propertyData{signature, std::move(getCallback), std::move(setCallback), flags}; - auto inserted = interface.properties_.emplace(propertyName, std::move(propertyData)).second; + InterfaceData::PropertyData propertyData{ std::move(signature) + , std::move(getCallback) + , std::move(setCallback) + , std::move(flags)}; + auto inserted = interface.properties.emplace(std::move(propertyName), std::move(propertyData)).second; SDBUS_THROW_ERROR_IF(!inserted, "Failed to register property: property already exists", EINVAL); } @@ -107,7 +142,7 @@ void Object::registerProperty( const std::string& interfaceName void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags) { auto& interface = interfaces_[interfaceName]; - interface.flags_ = flags; + interface.flags = flags; } void Object::finishRegistration() @@ -192,10 +227,10 @@ sdbus::IConnection& Object::getConnection() const const std::vector& Object::createInterfaceVTable(InterfaceData& interfaceData) { - auto& vtable = interfaceData.vtable_; + auto& vtable = interfaceData.vtable; assert(vtable.empty()); - vtable.push_back(createVTableStartItem(interfaceData.flags_.toSdBusInterfaceFlags())); + vtable.push_back(createVTableStartItem(interfaceData.flags.toSdBusInterfaceFlags())); registerMethodsToVTable(interfaceData, vtable); registerSignalsToVTable(interfaceData, vtable); registerPropertiesToVTable(interfaceData, vtable); @@ -206,14 +241,15 @@ const std::vector& Object::createInterfaceVTable(InterfaceData& i void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::vector& vtable) { - for (const auto& item : interfaceData.methods_) + for (const auto& item : interfaceData.methods) { const auto& methodName = item.first; const auto& methodData = item.second; vtable.push_back(createVTableMethodItem( methodName.c_str() - , methodData.inputArgs_.c_str() - , methodData.outputArgs_.c_str() + , methodData.inputArgs.c_str() + , methodData.outputArgs.c_str() + , methodData.paramNames.c_str() , &Object::sdbus_method_callback , methodData.flags_.toSdBusMethodFlags() )); } @@ -221,35 +257,36 @@ void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::ve void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::vector& vtable) { - for (const auto& item : interfaceData.signals_) + for (const auto& item : interfaceData.signals) { const auto& signalName = item.first; const auto& signalData = item.second; vtable.push_back(createVTableSignalItem( signalName.c_str() - , signalData.signature_.c_str() - , signalData.flags_.toSdBusSignalFlags() )); + , signalData.signature.c_str() + , signalData.paramNames.c_str() + , signalData.flags.toSdBusSignalFlags() )); } } void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector& vtable) { - for (const auto& item : interfaceData.properties_) + for (const auto& item : interfaceData.properties) { const auto& propertyName = item.first; const auto& propertyData = item.second; - if (!propertyData.setCallback_) + if (!propertyData.setCallback) vtable.push_back(createVTablePropertyItem( propertyName.c_str() - , propertyData.signature_.c_str() + , propertyData.signature.c_str() , &Object::sdbus_property_get_callback - , propertyData.flags_.toSdBusPropertyFlags() )); + , propertyData.flags.toSdBusPropertyFlags() )); else vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str() - , propertyData.signature_.c_str() + , propertyData.signature.c_str() , &Object::sdbus_property_get_callback , &Object::sdbus_property_set_callback - , propertyData.flags_.toSdBusWritablePropertyFlags() )); + , propertyData.flags.toSdBusWritablePropertyFlags() )); } } @@ -257,7 +294,15 @@ void Object::activateInterfaceVTable( const std::string& interfaceName , InterfaceData& interfaceData , const std::vector& vtable ) { - interfaceData.slot_ = connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], this); + interfaceData.slot = connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], this); +} + +std::string Object::paramNamesToString(const std::vector& paramNames) +{ + std::string names; + for (const auto& name : paramNames) + names += name + '\0'; + return names; } int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError) @@ -268,7 +313,7 @@ int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, auto message = Message::Factory::create(sdbusMessage, &object->connection_.getSdBusInterface()); // Note: The lookup can be optimized by using sorted vectors instead of associative containers - auto& callback = object->interfaces_[message.getInterfaceName()].methods_[message.getMemberName()].callback_; + auto& callback = object->interfaces_[message.getInterfaceName()].methods[message.getMemberName()].callback; assert(callback); try @@ -295,7 +340,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/ assert(object != nullptr); // Note: The lookup can be optimized by using sorted vectors instead of associative containers - auto& callback = object->interfaces_[interface].properties_[property].getCallback_; + auto& callback = object->interfaces_[interface].properties[property].getCallback; // Getter can be empty - the case of "write-only" property if (!callback) { @@ -329,7 +374,7 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/ assert(object != nullptr); // Note: The lookup can be optimized by using sorted vectors instead of associative containers - auto& callback = object->interfaces_[interface].properties_[property].setCallback_; + auto& callback = object->interfaces_[interface].properties[property].setCallback; assert(callback); auto value = Message::Factory::create(sdbusValue, &object->connection_.getSdBusInterface()); diff --git a/src/Object.h b/src/Object.h index 3c77c01..f5b4545 100644 --- a/src/Object.h +++ b/src/Object.h @@ -47,26 +47,38 @@ namespace internal { Object(sdbus::internal::IConnection& connection, std::string objectPath); void registerMethod( const std::string& interfaceName - , const std::string& methodName - , const std::string& inputSignature - , const std::string& outputSignature + , std::string methodName + , std::string inputSignature + , std::string outputSignature + , method_callback methodCallback + , Flags flags ) override; + void registerMethod( const std::string& interfaceName + , std::string methodName + , std::string inputSignature + , const std::vector& inputNames + , std::string outputSignature + , const std::vector& outputNames , method_callback methodCallback , Flags flags ) override; void registerSignal( const std::string& interfaceName - , const std::string& signalName - , const std::string& signature + , std::string signalName + , std::string signature + , Flags flags ) override; + void registerSignal( const std::string& interfaceName + , std::string signalName + , std::string signature + , const std::vector& paramNames , Flags flags ) override; void registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , Flags flags ) override; - void registerProperty( const std::string& interfaceName - , const std::string& propertyName - , const std::string& signature + , std::string propertyName + , std::string signature , property_get_callback getCallback , property_set_callback setCallback , Flags flags ) override; @@ -98,32 +110,34 @@ namespace internal { using MethodName = std::string; struct MethodData { - std::string inputArgs_; - std::string outputArgs_; - method_callback callback_; + const std::string inputArgs; + const std::string outputArgs; + const std::string paramNames; + method_callback callback; Flags flags_; }; - std::map methods_; + std::map methods; using SignalName = std::string; struct SignalData { - std::string signature_; - Flags flags_; + const std::string signature; + const std::string paramNames; + Flags flags; }; - std::map signals_; + std::map signals; using PropertyName = std::string; struct PropertyData { - std::string signature_; - property_get_callback getCallback_; - property_set_callback setCallback_; - Flags flags_; + const std::string signature; + property_get_callback getCallback; + property_set_callback setCallback; + Flags flags; }; - std::map properties_; - std::vector vtable_; - Flags flags_; + std::map properties; + std::vector vtable; + Flags flags; - SlotPtr slot_; + SlotPtr slot; }; static const std::vector& createInterfaceVTable(InterfaceData& interfaceData); @@ -133,6 +147,7 @@ namespace internal { void activateInterfaceVTable( const std::string& interfaceName , InterfaceData& interfaceData , const std::vector& vtable ); + static std::string paramNamesToString(const std::vector& paramNames); static int sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError); static int sdbus_property_get_callback( sd_bus *bus diff --git a/src/VTableUtils.c b/src/VTableUtils.c index 2c18208..964388f 100644 --- a/src/VTableUtils.c +++ b/src/VTableUtils.c @@ -36,18 +36,46 @@ sd_bus_vtable createVTableStartItem(uint64_t flags) sd_bus_vtable createVTableMethodItem( const char *member , const char *signature , const char *result + , const char *paramNames , sd_bus_message_handler_t handler , uint64_t flags ) { +#if LIBSYSTEMD_VERSION>=242 + // We have to expand macro SD_BUS_METHOD_WITH_NAMES manually here, because the macro expects literal char strings + /*struct sd_bus_vtable vtableItem = SD_BUS_METHOD_WITH_NAMES(member, signature, innames, result, outnames, handler, flags);*/ + struct sd_bus_vtable vtableItem = + { + .type = _SD_BUS_VTABLE_METHOD, + .flags = flags, + .x = { + .method = { + .member = member, + .signature = signature, + .result = result, + .handler = handler, + .offset = 0, + .names = paramNames, + }, + }, + }; +#else + (void)paramNames; struct sd_bus_vtable vtableItem = SD_BUS_METHOD(member, signature, result, handler, flags); +#endif return vtableItem; } sd_bus_vtable createVTableSignalItem( const char *member , const char *signature + , const char *outnames , uint64_t flags ) { +#if LIBSYSTEMD_VERSION>=242 + struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL_WITH_NAMES(member, signature, outnames, flags); +#else + (void)outnames; struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL(member, signature, flags); +#endif return vtableItem; } diff --git a/src/VTableUtils.h b/src/VTableUtils.h index 8981ca4..7881a56 100644 --- a/src/VTableUtils.h +++ b/src/VTableUtils.h @@ -38,10 +38,12 @@ sd_bus_vtable createVTableStartItem(uint64_t flags); sd_bus_vtable createVTableMethodItem( const char *member , const char *signature , const char *result + , const char *paramNames , sd_bus_message_handler_t handler , uint64_t flags ); sd_bus_vtable createVTableSignalItem( const char *member , const char *signature + , const char *outnames , uint64_t flags ); sd_bus_vtable createVTablePropertyItem( const char *member , const char *signature diff --git a/tests/integrationtests/adaptor-glue.h b/tests/integrationtests/adaptor-glue.h index d5d88d5..0fb4edc 100644 --- a/tests/integrationtests/adaptor-glue.h +++ b/tests/integrationtests/adaptor-glue.h @@ -60,17 +60,18 @@ protected: object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL); object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); }); - object_.registerMethod("getInt").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getInt(); }); + object_.registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); }); object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getTuple(); }); - object_.registerMethod("multiply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); }); + object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); }); object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply(); object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).implementedAs([this]( const sdbus::Struct>& x){ return this->getInts16FromStruct(x); }); object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Variant& v){ return this->processVariant(v); }); - object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).implementedAs([this]( + object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME) + .withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this]( const std::vector& x, const sdbus::Struct& y){ return this->getMapOfVariants(x ,y); }); object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getStructInStruct(); }); @@ -110,8 +111,9 @@ protected: // registration of signals is optional, it is useful because of introspection object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated(); - object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters>(); - object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters(); + // Note: sd-bus of libsystemd up to v244 has a bug where it doesn't generate signal parameter names in introspection XML. Signal param names commented temporarily. + object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters>(/*"aMap"*/); + object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters(/*"aVariant"*/); object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE); object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL); @@ -250,16 +252,16 @@ R"delimiter( - + - - - + + + @@ -278,9 +280,9 @@ R"delimiter( - - - + + + diff --git a/tests/perftests/perftests-adaptor.h b/tests/perftests/perftests-adaptor.h index db2f0df..e9dfca6 100644 --- a/tests/perftests/perftests-adaptor.h +++ b/tests/perftests/perftests-adaptor.h @@ -22,9 +22,9 @@ protected: perftests_adaptor(sdbus::IObject& object) : object_(object) { - object_.registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); }); - object_.registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); }); - object_.registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters(); + object_.registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); }); + object_.registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); }); + object_.registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters("data"); } ~perftests_adaptor() = default; diff --git a/tests/stresstests/celsius-thermometer-adaptor.h b/tests/stresstests/celsius-thermometer-adaptor.h index 6ef3df4..2d0a97a 100644 --- a/tests/stresstests/celsius-thermometer-adaptor.h +++ b/tests/stresstests/celsius-thermometer-adaptor.h @@ -24,7 +24,7 @@ protected: thermometer_adaptor(sdbus::IObject& object) : object_(object) { - object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getCurrentTemperature(); }); + object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); }); } ~thermometer_adaptor() = default; diff --git a/tests/stresstests/concatenator-adaptor.h b/tests/stresstests/concatenator-adaptor.h index 31c38f7..73309e5 100644 --- a/tests/stresstests/concatenator-adaptor.h +++ b/tests/stresstests/concatenator-adaptor.h @@ -23,8 +23,8 @@ protected: concatenator_adaptor(sdbus::IObject& object) : object_(object) { - object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result&& result, std::map params){ this->concatenate(std::move(result), std::move(params)); }); - object_.registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters(); + object_.registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result&& result, std::map params){ this->concatenate(std::move(result), std::move(params)); }); + object_.registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters("concatenatedString"); } ~concatenator_adaptor() = default; diff --git a/tests/stresstests/fahrenheit-thermometer-adaptor.h b/tests/stresstests/fahrenheit-thermometer-adaptor.h index 4af48d8..4a72cad 100644 --- a/tests/stresstests/fahrenheit-thermometer-adaptor.h +++ b/tests/stresstests/fahrenheit-thermometer-adaptor.h @@ -24,7 +24,7 @@ protected: thermometer_adaptor(sdbus::IObject& object) : object_(object) { - object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getCurrentTemperature(); }); + object_.registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); }); } ~thermometer_adaptor() = default; @@ -53,8 +53,8 @@ protected: factory_adaptor(sdbus::IObject& object) : object_(object) { - object_.registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result&& result){ this->createDelegateObject(std::move(result)); }); - object_.registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply(); + object_.registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result&& result){ this->createDelegateObject(std::move(result)); }); + object_.registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply(); } ~factory_adaptor() = default; diff --git a/tools/xml2cpp-codegen/AdaptorGenerator.cpp b/tools/xml2cpp-codegen/AdaptorGenerator.cpp index e7ec62c..0c94c3c 100644 --- a/tools/xml2cpp-codegen/AdaptorGenerator.cpp +++ b/tools/xml2cpp-codegen/AdaptorGenerator.cpp @@ -204,14 +204,17 @@ std::tuple AdaptorGenerator::processMethods(const Node Nodes inArgs = args.select("direction" , "in"); Nodes outArgs = args.select("direction" , "out"); - std::string argStr, argTypeStr; - std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(inArgs, async); + std::string argStr, argTypeStr, argStringsStr, outArgStringsStr; + std::tie(argStr, argTypeStr, std::ignore, argStringsStr) = argsToNamesAndTypes(inArgs, async); + std::tie(std::ignore, std::ignore, std::ignore, outArgStringsStr) = argsToNamesAndTypes(outArgs); using namespace std::string_literals; registrationSS << tab << tab << "object_.registerMethod(\"" << methodName << "\")" << ".onInterface(INTERFACE_NAME)" + << (!argStringsStr.empty() ? (".withInputParamNames(" + argStringsStr + ")") : "") + << (!outArgStringsStr.empty() ? (".withOutputParamNames(" + outArgStringsStr + ")") : "") << ".implementedAs(" << "[this](" << (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "") @@ -259,8 +262,8 @@ std::tuple AdaptorGenerator::processSignals(const Node Nodes args = (*signal)["arg"]; - std::string argStr, argTypeStr, typeStr;; - std::tie(argStr, argTypeStr, typeStr) = argsToNamesAndTypes(args); + std::string argStr, argTypeStr, typeStr, argStringsStr; + std::tie(argStr, argTypeStr, typeStr, argStringsStr) = argsToNamesAndTypes(args); signalRegistrationSS << tab << tab << "object_.registerSignal(\"" << name << "\")" @@ -268,7 +271,7 @@ std::tuple AdaptorGenerator::processSignals(const Node if (args.size() > 0) { - signalRegistrationSS << ".withParameters<" << typeStr << ">()"; + signalRegistrationSS << ".withParameters<" << typeStr << ">(" << argStringsStr << ")"; } signalRegistrationSS << annotationRegistration; diff --git a/tools/xml2cpp-codegen/BaseGenerator.cpp b/tools/xml2cpp-codegen/BaseGenerator.cpp index eec1842..f9bf896 100644 --- a/tools/xml2cpp-codegen/BaseGenerator.cpp +++ b/tools/xml2cpp-codegen/BaseGenerator.cpp @@ -105,9 +105,9 @@ std::tuple BaseGenerator::generateNamespaces(const std::s } -std::tuple BaseGenerator::argsToNamesAndTypes(const Nodes& args, bool async) const +std::tuple BaseGenerator::argsToNamesAndTypes(const Nodes& args, bool async) const { - std::ostringstream argSS, argTypeSS, typeSS; + std::ostringstream argSS, argTypeSS, typeSS, argStringsSS; for (size_t i = 0; i < args.size(); ++i) { @@ -115,6 +115,7 @@ std::tuple BaseGenerator::argsToNamesAndT if (i > 0) { argSS << ", "; + argStringsSS << ", "; argTypeSS << ", "; typeSS << ", "; } @@ -125,6 +126,7 @@ std::tuple BaseGenerator::argsToNamesAndT argName = "arg" + std::to_string(i); } auto type = signature_to_type(arg->get("type")); + argStringsSS << "\"" << argName << "\""; if (!async) { argSS << argName; @@ -138,7 +140,7 @@ std::tuple BaseGenerator::argsToNamesAndT typeSS << type; } - return std::make_tuple(argSS.str(), argTypeSS.str(), typeSS.str()); + return std::make_tuple(argSS.str(), argTypeSS.str(), typeSS.str(), argStringsSS.str()); } /** diff --git a/tools/xml2cpp-codegen/BaseGenerator.h b/tools/xml2cpp-codegen/BaseGenerator.h index 837149c..16f4c23 100644 --- a/tools/xml2cpp-codegen/BaseGenerator.h +++ b/tools/xml2cpp-codegen/BaseGenerator.h @@ -88,7 +88,7 @@ protected: * @param args * @return tuple: argument names, argument types and names, argument types */ - std::tuple argsToNamesAndTypes(const sdbuscpp::xml::Nodes& args, bool async = false) const; + std::tuple argsToNamesAndTypes(const sdbuscpp::xml::Nodes& args, bool async = false) const; /** * Output arguments to return type diff --git a/tools/xml2cpp-codegen/ProxyGenerator.cpp b/tools/xml2cpp-codegen/ProxyGenerator.cpp index e48c4fa..9e45944 100644 --- a/tools/xml2cpp-codegen/ProxyGenerator.cpp +++ b/tools/xml2cpp-codegen/ProxyGenerator.cpp @@ -169,9 +169,9 @@ std::tuple ProxyGenerator::processMethods(const Nodes& auto retType = outArgsToType(outArgs); std::string inArgStr, inArgTypeStr; - std::tie(inArgStr, inArgTypeStr, std::ignore) = argsToNamesAndTypes(inArgs); + std::tie(inArgStr, inArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(inArgs); std::string outArgStr, outArgTypeStr; - std::tie(outArgStr, outArgTypeStr, std::ignore) = argsToNamesAndTypes(outArgs); + std::tie(outArgStr, outArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(outArgs); definitionSS << tab << (async ? "void" : retType) << " " << name << "(" << inArgTypeStr << ")" << endl << tab << "{" << endl; @@ -239,7 +239,7 @@ std::tuple ProxyGenerator::processSignals(const Nodes& nameBigFirst[0] = islower(nameBigFirst[0]) ? nameBigFirst[0] + 'A' - 'a' : nameBigFirst[0]; std::string argStr, argTypeStr; - std::tie(argStr, argTypeStr, std::ignore) = argsToNamesAndTypes(args); + std::tie(argStr, argTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(args); registrationSS << tab << tab << "proxy_" ".uponSignal(\"" << name << "\")"