diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..68924642 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +# TODO: Introduce common clang-format rule set +DisableFormat: true +SortIncludes: false diff --git a/include/sdbus-c++/ConvenienceApiClasses.inl b/include/sdbus-c++/ConvenienceApiClasses.inl index 4ce3f436..d94ab309 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.inl +++ b/include/sdbus-c++/ConvenienceApiClasses.inl @@ -304,7 +304,7 @@ namespace sdbus { template inline async_reply_handler AsyncMethodInvoker::makeAsyncReplyHandler(Function&& callback) { - return [callback = std::forward(callback)](MethodReply reply, std::optional error) + return [callback = std::forward(callback)](MethodReply reply, std::optional error) mutable { // Create a tuple of callback input arguments' types, which will be used // as a storage for the argument values deserialized from the message. @@ -334,18 +334,18 @@ namespace sdbus { template std::future> AsyncMethodInvoker::getResultAsFuture() { - auto promise = std::make_shared>>(); - auto future = promise->get_future(); + std::promise> promise{}; + auto future = promise.get_future(); - uponReplyInvoke([promise = std::move(promise)](std::optional error, Args... args) + uponReplyInvoke([promise = std::move(promise)](std::optional error, Args... args) mutable { if (!error) if constexpr (!std::is_void_v>) - promise->set_value({std::move(args)...}); + promise.set_value({std::move(args)...}); else - promise->set_value(); + promise.set_value(); else - promise->set_exception(std::make_exception_ptr(*std::move(error))); + promise.set_exception(std::make_exception_ptr(*std::move(error))); }); // Will be std::future for no D-Bus method return value @@ -436,7 +436,7 @@ namespace sdbus { template inline signal_handler SignalSubscriber::makeSignalHandler(Function&& callback) { - return [callback = std::forward(callback)](Signal signal) + return [callback = std::forward(callback)](Signal signal) mutable { // Create a tuple of callback input arguments' types, which will be used // as a storage for the argument values deserialized from the signal message. diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h index f9758c71..02c591f6 100644 --- a/include/sdbus-c++/IConnection.h +++ b/include/sdbus-c++/IConnection.h @@ -277,7 +277,7 @@ namespace sdbus { * * @throws sdbus::Error in case of failure */ - virtual void addMatch(const std::string& match, message_handler callback) = 0; + virtual void addMatch(const std::string& match, message_handler&& callback) = 0; /*! * @brief Installs a match rule for messages received on this bus connection @@ -300,14 +300,14 @@ namespace sdbus { * * @throws sdbus::Error in case of failure */ - [[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler callback, return_slot_t) = 0; + [[nodiscard]] virtual Slot addMatch(const std::string& match, message_handler&& callback, return_slot_t) = 0; /*! * @brief Asynchronously installs a floating match rule for messages received on this bus connection * * @param[in] match Match expression to filter incoming D-Bus message * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule - * @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @param[in] installCallback One-shot handler invoked once with the broker's response to the install request * * This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously, * in a non-blocking fashion. A request is sent to the broker, but the call does not wait for a response. @@ -323,14 +323,14 @@ namespace sdbus { * * @throws sdbus::Error in case of failure */ - virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) = 0; + virtual void addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) = 0; /*! * @brief Asynchronously installs a match rule for messages received on this bus connection * * @param[in] match Match expression to filter incoming D-Bus message * @param[in] callback Callback handler to be called upon processing an inbound D-Bus message matching the rule - * @param[in] installCallback Callback handler to be called upon processing an inbound D-Bus message matching the rule + * @param[in] installCallback One-shot handler invoked once with the broker's response to the install request * @return RAII-style slot handle representing the ownership of the subscription * * This method operates the same as `addMatch()` above, just that it installs the match rule asynchronously, @@ -347,8 +347,8 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ [[nodiscard]] virtual Slot addMatchAsync( const std::string& match - , message_handler callback - , message_handler installCallback + , message_handler&& callback + , match_install_handler&& installCallback , return_slot_t ) = 0; /*! diff --git a/include/sdbus-c++/IObject.h b/include/sdbus-c++/IObject.h index d2f3002c..94e874ec 100644 --- a/include/sdbus-c++/IObject.h +++ b/include/sdbus-c++/IObject.h @@ -442,13 +442,23 @@ namespace sdbus { template void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items) { - addVTable(std::move(interfaceName), {std::forward(items)...}); + // Built via emplace_back rather than a braced initializer_list: items hold move-only + // callbacks, and initializer_list elements are const (copy-only). + std::vector vtable; + vtable.reserve(sizeof...(items)); + (vtable.emplace_back(std::forward(items)), ...); + addVTable(std::move(interfaceName), std::move(vtable)); } template VTableAdder IObject::addVTable(VTableItems&&... items) { - return addVTable(std::vector{std::forward(items)...}); + // Built via emplace_back rather than a braced initializer_list: items hold move-only + // callbacks, and initializer_list elements are const (copy-only). + std::vector vtable; + vtable.reserve(sizeof...(items)); + (vtable.emplace_back(std::forward(items)), ...); + return addVTable(std::move(vtable)); } inline VTableAdder IObject::addVTable(std::vector vtable) diff --git a/include/sdbus-c++/IProxy.h b/include/sdbus-c++/IProxy.h index ce00c890..c4c0f71a 100644 --- a/include/sdbus-c++/IProxy.h +++ b/include/sdbus-c++/IProxy.h @@ -455,7 +455,7 @@ namespace sdbus { * * @throws sdbus::Error in case of failure */ - virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) = 0; + virtual PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) = 0; /*! * @brief Calls method on the D-Bus object asynchronously @@ -480,7 +480,7 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ [[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , return_slot_t ) = 0; /*! @@ -506,7 +506,7 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ virtual PendingAsyncCall callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , uint64_t timeout ) = 0; /*! @@ -533,7 +533,7 @@ namespace sdbus { * @throws sdbus::Error in case of failure */ [[nodiscard]] virtual Slot callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , uint64_t timeout , return_slot_t ) = 0; @@ -542,7 +542,7 @@ namespace sdbus { */ template PendingAsyncCall callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , const std::chrono::duration& timeout ); /*! @@ -550,7 +550,7 @@ namespace sdbus { */ template [[nodiscard]] Slot callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , const std::chrono::duration& timeout , return_slot_t ); @@ -669,7 +669,7 @@ namespace sdbus { */ virtual void registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler ) = 0; + , signal_handler&& signalHandler ) = 0; /*! * @brief Registers a handler for the desired signal emitted by the D-Bus object @@ -689,7 +689,7 @@ namespace sdbus { */ [[nodiscard]] virtual Slot registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) = 0; protected: // Internal API for efficiency reasons used by high-level API helper classes @@ -700,10 +700,10 @@ namespace sdbus { [[nodiscard]] virtual MethodCall createMethodCall(const char* interfaceName, const char* methodName) const = 0; virtual void registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler ) = 0; + , signal_handler&& signalHandler ) = 0; [[nodiscard]] virtual Slot registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) = 0; }; @@ -759,7 +759,7 @@ namespace sdbus { template inline PendingAsyncCall IProxy::callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , const std::chrono::duration& timeout ) { auto microsecs = std::chrono::duration_cast(timeout); @@ -768,7 +768,7 @@ namespace sdbus { template inline Slot IProxy::callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , const std::chrono::duration& timeout , return_slot_t ) { diff --git a/include/sdbus-c++/TypeTraits.h b/include/sdbus-c++/TypeTraits.h index 5e6e9af0..4735ff5c 100644 --- a/include/sdbus-c++/TypeTraits.h +++ b/include/sdbus-c++/TypeTraits.h @@ -74,15 +74,21 @@ namespace sdbus { namespace sdbus { // Callbacks from sdbus-c++ - using method_callback = std::function; - using async_reply_handler = std::function error)>; - using signal_handler = std::function; - using message_handler = std::function; - using property_set_callback = std::function; - using property_get_callback = std::function; + // Repeatable server-side and client-side callbacks + using method_callback = std::move_only_function; + using property_set_callback = std::move_only_function; + using property_get_callback = std::move_only_function; + using signal_handler = std::move_only_function; + using message_handler = std::move_only_function; + + // One-shot callbacks: invoked exactly once (async reply arrives / match rule installed). + // Rvalue-qualified so the library must std::move to invoke, making the call-once contract + // visible at the call site and letting handlers move-consume captured resources. + using async_reply_handler = std::move_only_function error) &&>; + using match_install_handler = std::move_only_function; // Type-erased RAII-style handle to callbacks/subscriptions registered to sdbus-c++ - using Slot = std::unique_ptr>; + using Slot = std::unique_ptr>; // Tag specifying that an owning handle (so-called slot) of the logical resource shall be provided to the client struct return_slot_t { explicit return_slot_t() = default; }; @@ -380,6 +386,9 @@ namespace sdbus { static constexpr bool is_trivial_dbus_type = false; }; + template + concept valid_signature = signature_of::is_valid; + // To simplify conversions of arrays to C strings template constexpr auto as_null_terminated(std::array arr) @@ -508,6 +517,10 @@ namespace sdbus { struct function_traits> : function_traits {}; + template + struct function_traits> : function_traits + {}; + template constexpr auto is_async_method_v = function_traits::is_async; diff --git a/include/sdbus-c++/VTableItems.h b/include/sdbus-c++/VTableItems.h index ae57a00a..c1976cf1 100644 --- a/include/sdbus-c++/VTableItems.h +++ b/include/sdbus-c++/VTableItems.h @@ -38,14 +38,14 @@ namespace sdbus { struct MethodVTableItem { - template MethodVTableItem& implementedAs(Function&& callback); - MethodVTableItem& withInputParamNames(std::vector names); - template MethodVTableItem& withInputParamNames(String... names); - MethodVTableItem& withOutputParamNames(std::vector names); - template MethodVTableItem& withOutputParamNames(String... names); - MethodVTableItem& markAsDeprecated(); - MethodVTableItem& markAsPrivileged(); - MethodVTableItem& withNoReply(); + template MethodVTableItem&& implementedAs(Function&& callback) &&; + MethodVTableItem&& withInputParamNames(std::vector names) &&; + template MethodVTableItem&& withInputParamNames(String... names) &&; + MethodVTableItem&& withOutputParamNames(std::vector names) &&; + template MethodVTableItem&& withOutputParamNames(String... names) &&; + MethodVTableItem&& markAsDeprecated() &&; + MethodVTableItem&& markAsPrivileged() &&; + MethodVTableItem&& withNoReply() &&; MethodName name; Signature inputSignature; @@ -61,10 +61,10 @@ namespace sdbus { struct SignalVTableItem { - template SignalVTableItem& withParameters(); - template SignalVTableItem& withParameters(std::vector names); - template SignalVTableItem& withParameters(String... names); - SignalVTableItem& markAsDeprecated(); + template SignalVTableItem&& withParameters() &&; + template SignalVTableItem&& withParameters(std::vector names) &&; + template SignalVTableItem&& withParameters(String... names) &&; + SignalVTableItem&& markAsDeprecated() &&; SignalName name; Signature signature; @@ -77,11 +77,11 @@ namespace sdbus { struct PropertyVTableItem { - template PropertyVTableItem& withGetter(Function&& callback); - template PropertyVTableItem& withSetter(Function&& callback); - PropertyVTableItem& markAsDeprecated(); - PropertyVTableItem& markAsPrivileged(); - PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior); + template PropertyVTableItem&& withGetter(Function&& callback) &&; + template PropertyVTableItem&& withSetter(Function&& callback) &&; + PropertyVTableItem&& markAsDeprecated() &&; + PropertyVTableItem&& markAsPrivileged() &&; + PropertyVTableItem&& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&; PropertyName name; Signature signature; @@ -95,10 +95,10 @@ namespace sdbus { struct InterfaceFlagsVTableItem { - InterfaceFlagsVTableItem& markAsDeprecated(); - InterfaceFlagsVTableItem& markAsPrivileged(); - InterfaceFlagsVTableItem& withNoReplyMethods(); - InterfaceFlagsVTableItem& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior); + InterfaceFlagsVTableItem&& markAsDeprecated() &&; + InterfaceFlagsVTableItem&& markAsPrivileged() &&; + InterfaceFlagsVTableItem&& withNoReplyMethods() &&; + InterfaceFlagsVTableItem&& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) &&; Flags flags; }; diff --git a/include/sdbus-c++/VTableItems.inl b/include/sdbus-c++/VTableItems.inl index ee4e4e32..05f376e0 100644 --- a/include/sdbus-c++/VTableItems.inl +++ b/include/sdbus-c++/VTableItems.inl @@ -40,11 +40,11 @@ namespace sdbus { /*** -------------------- ***/ template - MethodVTableItem& MethodVTableItem::implementedAs(Function&& callback) + MethodVTableItem&& MethodVTableItem::implementedAs(Function&& callback) && { inputSignature = signature_of_function_input_arguments_v; outputSignature = signature_of_function_output_arguments_v; - callbackHandler = [callback = std::forward(callback)](MethodCall call) + callbackHandler = [callback = std::forward(callback)](MethodCall call) mutable { // Create a tuple of callback input arguments' types, which will be used // as a storage for the argument values deserialized from the message. @@ -71,58 +71,58 @@ namespace sdbus { } }; - return *this; + return std::move(*this); } - inline MethodVTableItem& MethodVTableItem::withInputParamNames(std::vector names) + inline MethodVTableItem&& MethodVTableItem::withInputParamNames(std::vector names) && { inputParamNames = std::move(names); - return *this; + return std::move(*this); } template - inline MethodVTableItem& MethodVTableItem::withInputParamNames(String... names) + inline MethodVTableItem&& MethodVTableItem::withInputParamNames(String... names) && { static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); - return withInputParamNames({names...}); + return std::move(*this).withInputParamNames({names...}); } - inline MethodVTableItem& MethodVTableItem::withOutputParamNames(std::vector names) + inline MethodVTableItem&& MethodVTableItem::withOutputParamNames(std::vector names) && { outputParamNames = std::move(names); - return *this; + return std::move(*this); } template - inline MethodVTableItem& MethodVTableItem::withOutputParamNames(String... names) + inline MethodVTableItem&& MethodVTableItem::withOutputParamNames(String... names) && { static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); - return withOutputParamNames({names...}); + return std::move(*this).withOutputParamNames({names...}); } - inline MethodVTableItem& MethodVTableItem::markAsDeprecated() + inline MethodVTableItem&& MethodVTableItem::markAsDeprecated() && { flags.set(Flags::DEPRECATED); - return *this; + return std::move(*this); } - inline MethodVTableItem& MethodVTableItem::markAsPrivileged() + inline MethodVTableItem&& MethodVTableItem::markAsPrivileged() && { flags.set(Flags::PRIVILEGED); - return *this; + return std::move(*this); } - inline MethodVTableItem& MethodVTableItem::withNoReply() + inline MethodVTableItem&& MethodVTableItem::withNoReply() && { flags.set(Flags::METHOD_NO_REPLY); - return *this; + return std::move(*this); } inline MethodVTableItem registerMethod(MethodName methodName) @@ -140,35 +140,35 @@ namespace sdbus { /*** -------------------- ***/ template - inline SignalVTableItem& SignalVTableItem::withParameters() + inline SignalVTableItem&& SignalVTableItem::withParameters() && { signature = signature_of_function_input_arguments_v; - return *this; + return std::move(*this); } template - inline SignalVTableItem& SignalVTableItem::withParameters(std::vector names) + inline SignalVTableItem&& SignalVTableItem::withParameters(std::vector names) && { paramNames = std::move(names); - return withParameters(); + return std::move(*this).template withParameters(); } template - inline SignalVTableItem& SignalVTableItem::withParameters(String... names) + inline SignalVTableItem&& SignalVTableItem::withParameters(String... names) && { static_assert(std::conjunction_v...>, "Parameter names must be (convertible to) strings"); static_assert(sizeof...(Args) == sizeof...(String), "Numbers of signal parameters and their names don't match"); - return withParameters({names...}); + return std::move(*this).template withParameters({names...}); } - inline SignalVTableItem& SignalVTableItem::markAsDeprecated() + inline SignalVTableItem&& SignalVTableItem::markAsDeprecated() && { flags.set(Flags::DEPRECATED); - return *this; + return std::move(*this); } inline SignalVTableItem registerSignal(SignalName signalName) @@ -186,7 +186,7 @@ namespace sdbus { /*** -------------------- ***/ template - inline PropertyVTableItem& PropertyVTableItem::withGetter(Function&& callback) + inline PropertyVTableItem&& PropertyVTableItem::withGetter(Function&& callback) && { static_assert(function_argument_count_v == 0, "Property getter function must not take any arguments"); static_assert(!std::is_void_v>, "Property getter function must return property value"); @@ -194,17 +194,17 @@ namespace sdbus { if (signature.empty()) signature = signature_of_function_output_arguments_v; - getter = [callback = std::forward(callback)](PropertyGetReply& reply) + getter = [callback = std::forward(callback)](PropertyGetReply& reply) mutable { // Get the propety value and serialize it into the pre-constructed reply message reply << callback(); }; - return *this; + return std::move(*this); } template - inline PropertyVTableItem& PropertyVTableItem::withSetter(Function&& callback) + inline PropertyVTableItem&& PropertyVTableItem::withSetter(Function&& callback) && { static_assert(function_argument_count_v == 1, "Property setter function must take one parameter - the property value"); static_assert(std::is_void_v>, "Property setter function must not return any value"); @@ -212,7 +212,7 @@ namespace sdbus { if (signature.empty()) signature = signature_of_function_input_arguments_v; - setter = [callback = std::forward(callback)](PropertySetCall call) + setter = [callback = std::forward(callback)](PropertySetCall call) mutable { // Default-construct property value using property_type = function_argument_t; @@ -225,28 +225,28 @@ namespace sdbus { callback(property); }; - return *this; + return std::move(*this); } - inline PropertyVTableItem& PropertyVTableItem::markAsDeprecated() + inline PropertyVTableItem&& PropertyVTableItem::markAsDeprecated() && { flags.set(Flags::DEPRECATED); - return *this; + return std::move(*this); } - inline PropertyVTableItem& PropertyVTableItem::markAsPrivileged() + inline PropertyVTableItem&& PropertyVTableItem::markAsPrivileged() && { flags.set(Flags::PRIVILEGED); - return *this; + return std::move(*this); } - inline PropertyVTableItem& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) + inline PropertyVTableItem&& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) && { flags.set(behavior); - return *this; + return std::move(*this); } inline PropertyVTableItem registerProperty(PropertyName propertyName) @@ -263,32 +263,32 @@ namespace sdbus { /*** Interface Flags VTable Item ***/ /*** --------------------------- ***/ - inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsDeprecated() + inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::markAsDeprecated() && { flags.set(Flags::DEPRECATED); - return *this; + return std::move(*this); } - inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsPrivileged() + inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::markAsPrivileged() && { flags.set(Flags::PRIVILEGED); - return *this; + return std::move(*this); } - inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withNoReplyMethods() + inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::withNoReplyMethods() && { flags.set(Flags::METHOD_NO_REPLY); - return *this; + return std::move(*this); } - inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) + inline InterfaceFlagsVTableItem&& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior) && { flags.set(behavior); - return *this; + return std::move(*this); } inline InterfaceFlagsVTableItem setInterfaceFlags() diff --git a/src/Connection.cpp b/src/Connection.cpp index 694a69dc..bf3b11b8 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -58,9 +58,9 @@ namespace sdbus::internal { -Connection::Connection(std::unique_ptr&& interface, const BusFactory& busFactory) +Connection::Connection(std::unique_ptr&& interface, BusFactory&& busFactory) : sdbus_(std::move(interface)) - , bus_(openBus(busFactory)) + , bus_(openBus(std::move(busFactory))) { assert(sdbus_ != nullptr); } @@ -238,12 +238,12 @@ uint64_t Connection::getMethodCallTimeout() const return timeout; } -void Connection::addMatch(const std::string& match, message_handler callback) +void Connection::addMatch(const std::string& match, message_handler&& callback) { floatingMatchRules_.push_back(addMatch(match, std::move(callback), return_slot)); } -Slot Connection::addMatch(const std::string& match, message_handler callback, return_slot_t) +Slot Connection::addMatch(const std::string& match, message_handler&& callback, return_slot_t) { SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL); @@ -258,14 +258,14 @@ Slot Connection::addMatch(const std::string& match, message_handler callback, re return {matchInfo.release(), [](void *ptr){ delete static_cast(ptr); }}; // NOLINT(cppcoreguidelines-owning-memory) } -void Connection::addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) +void Connection::addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) { floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback), return_slot)); } Slot Connection::addMatchAsync( const std::string& match - , message_handler callback - , message_handler installCallback + , message_handler&& callback + , match_install_handler&& installCallback , return_slot_t ) { SDBUS_THROW_ERROR_IF(!callback, "Invalid match callback handler provided", EINVAL); @@ -739,10 +739,10 @@ sd_bus_message* Connection::createErrorReplyMessage(sd_bus_message* sdbusMsg, co return sdbusErrorReply; } -Connection::BusPtr Connection::openBus(const BusFactory& busFactory) +Connection::BusPtr Connection::openBus(BusFactory&& busFactory) { sd_bus* bus{}; - const int r = busFactory(&bus); + const int r = std::move(busFactory)(&bus); SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r); BusPtr busPtr{bus, [this](sd_bus* bus){ return sdbus_->sd_bus_flush_close_unref(bus); }}; @@ -920,7 +920,7 @@ int Connection::sdbus_match_install_callback(sd_bus_message *sdbusMessage, void auto message = Message::Factory::create(sdbusMessage, &matchInfo->connection); - auto ok = invokeHandlerAndCatchErrors([&](){ matchInfo->installCallback(std::move(message)); }, retError); + auto ok = invokeHandlerAndCatchErrors([&](){ std::move(matchInfo->installCallback)(std::move(message)); }, retError); return ok ? 0 : -1; } diff --git a/src/Connection.h b/src/Connection.h index 0e63aa6b..2925f383 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -111,12 +111,12 @@ namespace sdbus::internal { void setMethodCallTimeout(uint64_t timeout) override; [[nodiscard]] uint64_t getMethodCallTimeout() const override; - void addMatch(const std::string& match, message_handler callback) override; - [[nodiscard]] Slot addMatch(const std::string& match, message_handler callback, return_slot_t) override; - void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) override; + void addMatch(const std::string& match, message_handler&& callback) override; + [[nodiscard]] Slot addMatch(const std::string& match, message_handler&& callback, return_slot_t) override; + void addMatchAsync(const std::string& match, message_handler&& callback, match_install_handler&& installCallback) override; [[nodiscard]] Slot addMatchAsync( const std::string& match - , message_handler callback - , message_handler installCallback + , message_handler&& callback + , match_install_handler&& installCallback , return_slot_t ) override; void attachSdEventLoop(sd_event *event, int priority) override; @@ -181,11 +181,11 @@ namespace sdbus::internal { sd_bus_message* createErrorReplyMessage(sd_bus_message* sdbusMsg, const Error& error) override; private: - using BusFactory = std::function; - using BusPtr = std::unique_ptr>; - Connection(std::unique_ptr&& interface, const BusFactory& busFactory); + using BusFactory = std::move_only_function; + using BusPtr = std::unique_ptr>; + Connection(std::unique_ptr&& interface, BusFactory&& busFactory); - BusPtr openBus(const std::function& busFactory); + BusPtr openBus(BusFactory&& busFactory); BusPtr openPseudoBus(); void finishHandshake(sd_bus* bus); bool waitForNextEvent(); @@ -234,7 +234,7 @@ namespace sdbus::internal { struct MatchInfo { message_handler callback; - message_handler installCallback; + match_install_handler installCallback; Connection& connection; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) Slot slot; }; diff --git a/src/Object.cpp b/src/Object.cpp index 7ddd1857..ef4d03cf 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -300,7 +300,7 @@ void Object::finalizeSdBusVTable(std::vector& vtable) vtable.push_back(createSdBusVTableEndItem()); } -const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, std::string_view methodName) +Object::VTable::MethodItem* Object::findMethod(VTable& vtable, std::string_view methodName) { auto it = std::lower_bound(vtable.methods.begin(), vtable.methods.end(), methodName, [](const auto& methodItem, const auto& methodName) { @@ -310,7 +310,7 @@ const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, std:: return it != vtable.methods.end() && it->name == methodName ? &*it : nullptr; } -const Object::VTable::PropertyItem* Object::findProperty(const VTable& vtable, std::string_view propertyName) +Object::VTable::PropertyItem* Object::findProperty(VTable& vtable, std::string_view propertyName) { auto it = std::lower_bound(vtable.properties.begin(), vtable.properties.end(), propertyName, [](const auto& propertyItem, const auto& propertyName) { @@ -336,11 +336,11 @@ int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, auto message = Message::Factory::create(sdbusMessage, &vtable->object->connection_); - const auto* methodItem = findMethod(*vtable, message.getMemberName()); + auto* methodItem = findMethod(*vtable, message.getMemberName()); assert(methodItem != nullptr); assert(methodItem->callback); - auto ok = invokeHandlerAndCatchErrors([&](){ methodItem->callback(std::move(message)); }, retError); + auto ok = invokeHandlerAndCatchErrors([&] { methodItem->callback(std::move(message)); }, retError); return ok ? 1 : -1; } @@ -357,7 +357,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/ assert(vtable != nullptr); assert(vtable->object != nullptr); - const auto* propertyItem = findProperty(*vtable, property); + auto* propertyItem = findProperty(*vtable, property); assert(propertyItem != nullptr); // Getter may be empty - the case of "write-only" property @@ -369,7 +369,7 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/ auto reply = Message::Factory::create(sdbusReply, &vtable->object->connection_); - auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->getCallback(reply); }, retError); + auto ok = invokeHandlerAndCatchErrors([&] { propertyItem->getCallback(reply); }, retError); return ok ? 1 : -1; } @@ -386,13 +386,13 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/ assert(vtable != nullptr); assert(vtable->object != nullptr); - const auto* propertyItem = findProperty(*vtable, property); + auto* propertyItem = findProperty(*vtable, property); assert(propertyItem != nullptr); assert(propertyItem->setCallback); auto value = Message::Factory::create(sdbusValue, &vtable->object->connection_); - auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->setCallback(std::move(value)); }, retError); + auto ok = invokeHandlerAndCatchErrors([&] { propertyItem->setCallback(std::move(value)); }, retError); return ok ? 1 : -1; } diff --git a/src/Object.h b/src/Object.h index 4dafa6b3..1dccac45 100644 --- a/src/Object.h +++ b/src/Object.h @@ -145,8 +145,8 @@ namespace sdbus::internal { static void writePropertyRecordToSdBusVTable(const VTable::PropertyItem& property, std::vector& vtable); static void finalizeSdBusVTable(std::vector& vtable); - static const VTable::MethodItem* findMethod(const VTable& vtable, std::string_view methodName); - static const VTable::PropertyItem* findProperty(const VTable& vtable, std::string_view propertyName); + static VTable::MethodItem* findMethod(VTable& vtable, std::string_view methodName); + static VTable::PropertyItem* findProperty(VTable& vtable, std::string_view propertyName); static std::string paramNamesToString(const std::vector& paramNames); diff --git a/src/Proxy.cpp b/src/Proxy.cpp index 1c5377f3..0f6e8135 100644 --- a/src/Proxy.cpp +++ b/src/Proxy.cpp @@ -117,17 +117,17 @@ MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout) return message.send(timeout); } -PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) +PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) { return Proxy::callMethodAsync(message, std::move(asyncReplyCallback), /*timeout*/ 0); } -Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, return_slot_t) +Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, return_slot_t) { return Proxy::callMethodAsync(message, std::move(asyncReplyCallback), /*timeout*/ 0, return_slot); } -PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) +PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, uint64_t timeout) { SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL); @@ -145,7 +145,7 @@ PendingAsyncCall Proxy::callMethodAsync(const MethodCall& message, async_reply_h return PendingAsyncCall{asyncCallInfoWeakPtr}; } -Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout, return_slot_t) +Slot Proxy::callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback, uint64_t timeout, return_slot_t) { SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL); @@ -166,15 +166,15 @@ std::future Proxy::callMethodAsync(const MethodCall& message, with_ std::future Proxy::callMethodAsync(const MethodCall& message, uint64_t timeout, with_future_t) { - auto promise = std::make_shared>(); - auto future = promise->get_future(); + std::promise promise; + auto future = promise.get_future(); - async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply reply, std::optional error) noexcept + async_reply_handler asyncReplyCallback = [promise = std::move(promise)](MethodReply reply, std::optional error) mutable noexcept { if (!error) - promise->set_value(std::move(reply)); + promise.set_value(std::move(reply)); else - promise->set_exception(std::make_exception_ptr(*std::move(error))); + promise.set_exception(std::make_exception_ptr(*std::move(error))); }; (void)Proxy::callMethodAsync(message, std::move(asyncReplyCallback), timeout); @@ -209,14 +209,14 @@ Awaitable Proxy::callMethodAsync(const MethodCall& message, uint64_ void Proxy::registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler ) + , signal_handler&& signalHandler ) { Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler)); } void Proxy::registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler ) + , signal_handler&& signalHandler ) { auto slot = Proxy::registerSignalHandler(interfaceName, signalName, std::move(signalHandler), return_slot); @@ -225,7 +225,7 @@ void Proxy::registerSignalHandler( const char* interfaceName Slot Proxy::registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) { return Proxy::registerSignalHandler(interfaceName.c_str(), signalName.c_str(), std::move(signalHandler), return_slot); @@ -233,7 +233,7 @@ Slot Proxy::registerSignalHandler( const InterfaceName& interfaceName Slot Proxy::registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) { SDBUS_CHECK_INTERFACE_NAME(interfaceName); @@ -296,12 +296,12 @@ int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userDat const auto* error = sd_bus_message_get_error(sdbusMessage); if (error == nullptr) { - asyncCallInfo->callback(std::move(message), {}); + std::move(asyncCallInfo->callback)(std::move(message), {}); } else { Error exception(Error::Name{error->name}, error->message); - asyncCallInfo->callback(std::move(message), std::move(exception)); + std::move(asyncCallInfo->callback)(std::move(message), std::move(exception)); } }, retError); diff --git a/src/Proxy.h b/src/Proxy.h index 0d496413..d76c82df 100644 --- a/src/Proxy.h +++ b/src/Proxy.h @@ -60,15 +60,15 @@ namespace sdbus::internal { [[nodiscard]] MethodCall createMethodCall(const char* interfaceName, const char* methodName) const override; MethodReply callMethod(const MethodCall& message) override; MethodReply callMethod(const MethodCall& message, uint64_t timeout) override; - PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler asyncReplyCallback) override; + PendingAsyncCall callMethodAsync(const MethodCall& message, async_reply_handler&& asyncReplyCallback) override; Slot callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , return_slot_t ) override; PendingAsyncCall callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , uint64_t timeout ) override; Slot callMethodAsync( const MethodCall& message - , async_reply_handler asyncReplyCallback + , async_reply_handler&& asyncReplyCallback , uint64_t timeout , return_slot_t ) override; std::future callMethodAsync(const MethodCall& message, with_future_t) override; @@ -80,17 +80,17 @@ namespace sdbus::internal { void registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler ) override; + , signal_handler&& signalHandler ) override; void registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler ) override; + , signal_handler&& signalHandler ) override; Slot registerSignalHandler( const InterfaceName& interfaceName , const SignalName& signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) override; Slot registerSignalHandler( const char* interfaceName , const char* signalName - , signal_handler signalHandler + , signal_handler&& signalHandler , return_slot_t ) override; void unregister() override; @@ -104,7 +104,7 @@ namespace sdbus::internal { friend PendingAsyncCall; - std::unique_ptr> connection_; + std::unique_ptr> connection_; ServiceName destination_; ObjectPath objectPath_; diff --git a/src/Utils.h b/src/Utils.h index 4164d723..a6bfd523 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -57,11 +57,11 @@ namespace sdbus::internal { template - bool invokeHandlerAndCatchErrors(Callable callable, sd_bus_error *retError) + bool invokeHandlerAndCatchErrors(Callable&& callable, sd_bus_error *retError) { try { - callable(); + std::forward(callable)(); } catch (const Error& e) { diff --git a/tests/integrationtests/DBusMethodsTests.cpp b/tests/integrationtests/DBusMethodsTests.cpp index 345cf4e4..a0fd0846 100644 --- a/tests/integrationtests/DBusMethodsTests.cpp +++ b/tests/integrationtests/DBusMethodsTests.cpp @@ -350,10 +350,9 @@ TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime) { auto& object = this->m_adaptor->getObject(); sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"}; - auto vtableSlot = object.addVTable( interfaceName - , { sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; }) - , sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) } - , sdbus::return_slot ); + auto vtableSlot = object.addVTable( sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; }) + , sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) + ).forInterface(interfaceName, sdbus::return_slot); // The new remote vtable is registered as long as we keep vtableSlot, so remote method calls now should pass auto proxy = sdbus::createLightWeightProxy(SERVICE_NAME, OBJECT_PATH); @@ -367,11 +366,10 @@ TYPED_TEST(SdbusTestObject, CanUnregisterAdditionallyRegisteredVTableAtAnyTime) { auto& object = this->m_adaptor->getObject(); sdbus::InterfaceName const interfaceName{"org.sdbuscpp.integrationtests2"}; + auto vtableSlot = object.addVTable( sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; }) + , sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) + ).forInterface(interfaceName, sdbus::return_slot); - auto vtableSlot = object.addVTable( interfaceName - , { sdbus::registerMethod("add").implementedAs([](const double& lhs, const double& rhs){ return lhs + rhs; }) - , sdbus::registerMethod("subtract").implementedAs([](const int& lhs, const int& rhs){ return lhs - rhs; }) } - , sdbus::return_slot ); vtableSlot.reset(); // Letting the slot go means letting go the associated vtable registration // No such remote D-Bus method under given interface exists anymore...