diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h index a95ee20..c8b82c4 100644 --- a/include/sdbus-c++/IConnection.h +++ b/include/sdbus-c++/IConnection.h @@ -64,31 +64,6 @@ namespace sdbus { virtual ~IConnection() = default; - /*! - * @brief Requests a well-known D-Bus service name on a bus - * - * @param[in] name Name to request - * - * @throws sdbus::Error in case of failure - */ - virtual void requestName(const ServiceName& name) = 0; - - /*! - * @brief Releases an acquired well-known D-Bus service name on a bus - * - * @param[in] name Name to release - * - * @throws sdbus::Error in case of failure - */ - virtual void releaseName(const ServiceName& name) = 0; - - /*! - * @brief Retrieves the unique name of a connection. E.g. ":1.xx" - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] virtual BusName getUniqueName() const = 0; - /*! * @brief Enters I/O event loop on this bus connection * @@ -342,6 +317,31 @@ namespace sdbus { */ virtual void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) = 0; + /*! + * @brief Retrieves the unique name of a connection. E.g. ":1.xx" + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual BusName getUniqueName() const = 0; + + /*! + * @brief Requests a well-known D-Bus service name on a bus + * + * @param[in] name Name to request + * + * @throws sdbus::Error in case of failure + */ + virtual void requestName(const ServiceName& name) = 0; + + /*! + * @brief Releases an acquired well-known D-Bus service name on a bus + * + * @param[in] name Name to release + * + * @throws sdbus::Error in case of failure + */ + virtual void releaseName(const ServiceName& name) = 0; + /*! * @struct PollData * diff --git a/include/sdbus-c++/IObject.h b/include/sdbus-c++/IObject.h index 2606c87..3458fa6 100644 --- a/include/sdbus-c++/IObject.h +++ b/include/sdbus-c++/IObject.h @@ -61,80 +61,33 @@ namespace sdbus { ***********************************************/ class IObject { - public: + public: // High-level, convenience API virtual ~IObject() = default; /*! * @brief Adds a declaration of methods, properties and signals of the object at a given interface * - * @param[in] interfaceName Name of an interface the the vtable is registered for - * @param[in] items Individual instances of VTable item structures + * @param[in] vtable Individual instances of VTable item structures stored in a vector + * @return VTableAdder high-level helper class * * This method is used to declare attributes for the object under the given interface. - * Parameter `items' represents a vtable definition that may contain method declarations + * Parameter `vtable' represents a vtable definition that may contain method declarations * (using MethodVTableItem struct), property declarations (using PropertyVTableItem * struct), signal declarations (using SignalVTableItem struct), or global interface * flags (using InterfaceFlagsVTableItem struct). * * An interface can have any number of vtables attached to it. * - * Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information. + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. * - * The method can be called at any time during object's lifetime. For each vtable an internal - * match slot is created and its lifetime is tied to the lifetime of the Object instance. + * The method can be called at any time during object's lifetime. * - * The function provides strong exception guarantee. The state of the object remains - * unmodified in face of an exception. - * - * @throws sdbus::Error in case of failure - */ - template < typename... VTableItems - , typename = std::enable_if_t<(is_one_of_variants_types> && ...)> > - void addVTable(InterfaceName interfaceName, VTableItems&&... items); - - /*! - * @brief Adds a declaration of methods, properties and signals of the object at a given interface - * - * @param[in] interfaceName Name of an interface the the vtable is registered for - * @param[in] vtable A list of individual descriptions in the form of VTable item instances - * - * This method is used to declare attributes for the object under the given interface. - * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), - * property declarations (using PropertyVTableItem struct), signal declarations (using - * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). - * - * An interface can have any number of vtables attached to it. - * - * Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information. - * - * The method can be called at any time during object's lifetime. For each vtable an internal - * match slot is created and its lifetime is tied to the lifetime of the Object instance. - * - * The function provides strong exception guarantee. The state of the object remains - * unmodified in face of an exception. - * - * @throws sdbus::Error in case of failure - */ - virtual void addVTable(InterfaceName interfaceName, std::vector vtable) = 0; - - /*! - * @brief Adds a declaration of methods, properties and signals of the object at a given interface - * - * @param[in] interfaceName Name of an interface the the vtable is registered for - * @param[in] vtable A list of individual descriptions in the form of VTable item instances - * - * This method is used to declare attributes for the object under the given interface. - * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), - * property declarations (using PropertyVTableItem struct), signal declarations (using - * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). - * - * An interface can have any number of vtables attached to it. - * - * Consult manual pages for underlying `sd_bus_add_object_vtable` function for more information. - * - * The method can be called at any time during object's lifetime. For each vtable an internal - * match slot is created and is returned to the caller. The returned slot should be destroyed - * when the vtable is not needed anymore. This allows for "dynamic" object API where vtables + * When called like `addVTable(vtable).forInterface(interface)`, then an internal registration + * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance. + * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal + * registration slot is created for the vtable and is returned to the caller. Keeping the slot means + * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore, + * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables * can be added or removed by the user at runtime. * * The function provides strong exception guarantee. The state of the object remains @@ -142,66 +95,43 @@ namespace sdbus { * * @throws sdbus::Error in case of failure */ - [[nodiscard]] virtual Slot addVTable(InterfaceName interfaceName, std::vector vtable, return_slot_t) = 0; + [[nodiscard]] VTableAdder addVTable(std::vector vtable); /*! - * @brief A little more convenient overload of addVTable() above + * @brief Adds a declaration of methods, properties and signals of the object at a given interface * - * This version allows method chaining for a little safer and more readable VTable registration. + * @param[in] items Individual instances of VTable item structures + * @return VTableAdder high-level helper class * - * See addVTable() overloads above for detailed documentation. + * This method is used to declare attributes for the object under the given interface. + * Parameter pack contains vtable definition that may contain method declarations + * (using MethodVTableItem struct), property declarations (using PropertyVTableItem + * struct), signal declarations (using SignalVTableItem struct), or global interface + * flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. + * + * When called like `addVTable(items...).forInterface(interface)`, then an internal registration + * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance. + * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal + * registration slot is created for the vtable and is returned to the caller. Keeping the slot means + * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore, + * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables + * can be added or removed by the user at runtime. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure */ template < typename... VTableItems , typename = std::enable_if_t<(is_one_of_variants_types> && ...)> > [[nodiscard]] VTableAdder addVTable(VTableItems&&... items); - /*! - * @brief A little more convenient overload of addVTable() above - * - * This version allows method chaining for a little safer and more readable VTable registration. - * - * See addVTable() overloads above for detailed documentation. - */ - [[nodiscard]] VTableAdder addVTable(std::vector vtable); - - /*! - * @brief Unregisters object's API and removes object from the bus - * - * This method unregisters the object, its interfaces, methods, signals and properties - * from the bus. Unregistration is done automatically also in object's destructor. This - * method makes sense if, in the process of object removal, we need to make sure that - * callbacks are unregistered explicitly before the final destruction of the object instance. - * - * @throws sdbus::Error in case of failure - */ - virtual void unregister() = 0; - - /*! - * @brief Creates a signal message - * - * @param[in] interfaceName Name of an interface that the signal belongs under - * @param[in] signalName Name of the signal - * @return A signal message - * - * Serialize signal arguments into the returned message and emit the signal by passing - * the message with serialized arguments to the @c emitSignal function. - * Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below. - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] virtual Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) = 0; - - /*! - * @brief Emits signal for this object path - * - * @param[in] message Signal message to be sent out - * - * Note: To avoid messing with messages, use higher-level API defined below. - * - * @throws sdbus::Error in case of failure - */ - virtual void emitSignal(const sdbus::Signal& message) = 0; - /*! * @brief Emits signal on D-Bus * @@ -361,7 +291,126 @@ namespace sdbus { */ [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; - protected: + /*! + * @brief Unregisters object's API and removes object from the bus + * + * This method unregisters the object, its interfaces, methods, signals and properties + * from the bus. Unregistration is done automatically also in object's destructor. This + * method makes sense if, in the process of object removal, we need to make sure that + * callbacks are unregistered explicitly before the final destruction of the object instance. + * + * @throws sdbus::Error in case of failure + */ + virtual void unregister() = 0; + + public: // Lower-level, message-based API + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] items Individual instances of VTable item structures + * + * This method is used to declare attributes for the object under the given interface. + * Parameter `items' represents a vtable definition that may contain method declarations + * (using MethodVTableItem struct), property declarations (using PropertyVTableItem + * struct), signal declarations (using SignalVTableItem struct), or global interface + * flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and its lifetime is tied to the lifetime of the Object instance. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + template < typename... VTableItems + , typename = std::enable_if_t<(is_one_of_variants_types> && ...)> > + void addVTable(InterfaceName interfaceName, VTableItems&&... items); + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] vtable A list of individual descriptions in the form of VTable item instances + * + * This method is used to declare attributes for the object under the given interface. + * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), + * property declarations (using PropertyVTableItem struct), signal declarations (using + * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and its lifetime is tied to the lifetime of the Object instance. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + virtual void addVTable(InterfaceName interfaceName, std::vector vtable) = 0; + + /*! + * @brief Adds a declaration of methods, properties and signals of the object at a given interface + * + * @param[in] interfaceName Name of an interface the the vtable is registered for + * @param[in] vtable A list of individual descriptions in the form of VTable item instances + * + * This method is used to declare attributes for the object under the given interface. + * The `vtable' parameter may contain method declarations (using MethodVTableItem struct), + * property declarations (using PropertyVTableItem struct), signal declarations (using + * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct). + * + * An interface can have any number of vtables attached to it. + * + * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information. + * + * The method can be called at any time during object's lifetime. For each vtable an internal + * registration slot is created and is returned to the caller. The returned slot should be destroyed + * when the vtable is not needed anymore. This allows for "dynamic" object API where vtables + * can be added or removed by the user at runtime. + * + * The function provides strong exception guarantee. The state of the object remains + * unmodified in face of an exception. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Slot addVTable(InterfaceName interfaceName, std::vector vtable, return_slot_t) = 0; + + /*! + * @brief Creates a signal message + * + * @param[in] interfaceName Name of an interface that the signal belongs under + * @param[in] signalName Name of the signal + * @return A signal message + * + * Serialize signal arguments into the returned message and emit the signal by passing + * the message with serialized arguments to the @c emitSignal function. + * Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below. + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] virtual Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) = 0; + + /*! + * @brief Emits signal for this object path + * + * @param[in] message Signal message to be sent out + * + * Note: To avoid messing with messages, use higher-level API defined below. + * + * @throws sdbus::Error in case of failure + */ + virtual void emitSignal(const sdbus::Signal& message) = 0; + + protected: // Internal API for efficiency reasons used by high-level API helper classes friend SignalEmitter; [[nodiscard]] virtual Signal createSignal(const char* interfaceName, const char* signalName) = 0; diff --git a/include/sdbus-c++/IProxy.h b/include/sdbus-c++/IProxy.h index 9ea16a6..029127f 100644 --- a/include/sdbus-c++/IProxy.h +++ b/include/sdbus-c++/IProxy.h @@ -67,9 +67,290 @@ namespace sdbus { ***********************************************/ class IProxy { - public: + public: // High-level, convenience API virtual ~IProxy() = default; + /*! + * @brief Calls method on the D-Bus object + * + * @param[in] methodName Name of the method + * @return A helper object for convenient invocation of the method + * + * This is a high-level, convenience way of calling D-Bus methods that abstracts + * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized + * in a message and D-Bus signatures automatically deduced from the provided native arguments + * and return values. + * + * Example of use: + * @code + * int result, a = ..., b = ...; + * MethodName multiply{"multiply"}; + * object_.callMethod(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] MethodInvoker callMethod(const MethodName& methodName); + + /*! + * @copydoc IProxy::callMethod(const MethodName&) + */ + [[nodiscard]] MethodInvoker callMethod(const std::string& methodName); + + /*! + * @copydoc IProxy::callMethod(const MethodName&) + */ + [[nodiscard]] MethodInvoker callMethod(const char* methodName); + + /*! + * @brief Calls method on the D-Bus object asynchronously + * + * @param[in] methodName Name of the method + * @return A helper object for convenient asynchronous invocation of the method + * + * This is a high-level, convenience way of calling D-Bus methods that abstracts + * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized + * in a message and D-Bus signatures automatically deduced from the provided native arguments + * and return values. + * + * Example of use: + * @code + * int a = ..., b = ...; + * MethodName multiply{"multiply"}; + * object_.callMethodAsync(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result) + * { + * std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl; + * }); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const MethodName& methodName); + + /*! + * @copydoc IProxy::callMethodAsync(const MethodName&) + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName); + + /*! + * @copydoc IProxy::callMethodAsync(const MethodName&) + */ + [[nodiscard]] AsyncMethodInvoker callMethodAsync(const char* methodName); + + /*! + * @brief Registers signal handler for a given signal of the D-Bus object + * + * @param[in] signalName Name of the signal + * @return A helper object for convenient registration of the signal handler + * + * This is a high-level, convenience way of registering to D-Bus signals that abstracts + * from the D-Bus message concept. Signal arguments are automatically serialized + * in a message and D-Bus signatures automatically deduced from the parameters + * of the provided native signal callback. + * + * A signal can be subscribed to and unsubscribed from at any time during proxy + * lifetime. The subscription is active immediately after the call. + * + * Example of use: + * @code + * object_.uponSignal("stateChanged").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onStateChanged(arg1, arg2); }); + * sdbus::InterfaceName foo{"com.kistler.foo"}; + * sdbus::SignalName levelChanged{"levelChanged"}; + * object_.uponSignal(levelChanged).onInterface(foo).call([this](uint16_t level){ this->onLevelChanged(level); }); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] SignalSubscriber uponSignal(const SignalName& signalName); + + /*! + * @copydoc IProxy::uponSignal(const SignalName&) + */ + [[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName); + + /*! + * @copydoc IProxy::uponSignal(const SignalName&) + */ + [[nodiscard]] SignalSubscriber uponSignal(const char* signalName); + + /*! + * @brief Gets value of a property of the D-Bus object + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient getting of property value + * + * This is a high-level, convenience way of reading D-Bus property values that abstracts + * from the D-Bus message concept. sdbus::Variant is returned which shall then be converted + * to the real property type (implicit conversion is supported). + * + * Example of use: + * @code + * int state = object.getProperty("state").onInterface("com.kistler.foo"); + * sdbus::InterfaceName foo{"com.kistler.foo"}; + * sdbus::PropertyName level{"level"}; + * int level = object.getProperty(level).onInterface(foo); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] PropertyGetter getProperty(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::getProperty(const PropertyName&) + */ + [[nodiscard]] PropertyGetter getProperty(std::string_view propertyName); + + /*! + * @brief Gets value of a property of the D-Bus object asynchronously + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient asynchronous getting of property value + * + * This is a high-level, convenience way of reading D-Bus property values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * std::future state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture(); + * auto callback = [](std::optional err, const sdbus::Variant& value){ ... }; + * object.getPropertyAsync("state").onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncPropertyGetter getPropertyAsync(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::getPropertyAsync(const PropertyName&) + */ + [[nodiscard]] AsyncPropertyGetter getPropertyAsync(std::string_view propertyName); + + /*! + * @brief Sets value of a property of the D-Bus object + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient setting of property value + * + * This is a high-level, convenience way of writing D-Bus property values that abstracts + * from the D-Bus message concept. + * Setting property value with NoReply flag is also supported. + * + * Example of use: + * @code + * int state = ...; + * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state); + * // Or we can just send the set message call without waiting for the reply + * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state, dont_expect_reply); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] PropertySetter setProperty(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::setProperty(const PropertyName&) + */ + [[nodiscard]] PropertySetter setProperty(std::string_view propertyName); + + /*! + * @brief Sets value of a property of the D-Bus object asynchronously + * + * @param[in] propertyName Name of the property + * @return A helper object for convenient asynchronous setting of property value + * + * This is a high-level, convenience way of writing D-Bus property values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * int state = ...; + * // We can wait until the set operation finishes by waiting on the future + * std::future res = object_.setPropertyAsync("state").onInterface("com.kistler.foo").toValue(state).getResultAsFuture(); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncPropertySetter setPropertyAsync(const PropertyName& propertyName); + + /*! + * @copydoc IProxy::setPropertyAsync(const PropertyName&) + */ + [[nodiscard]] AsyncPropertySetter setPropertyAsync(std::string_view propertyName); + + /*! + * @brief Gets values of all properties of the D-Bus object + * + * @return A helper object for convenient getting of properties' values + * + * This is a high-level, convenience way of reading D-Bus properties' values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * auto props = object.getAllProperties().onInterface("com.kistler.foo"); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AllPropertiesGetter getAllProperties(); + + /*! + * @brief Gets values of all properties of the D-Bus object asynchronously + * + * @return A helper object for convenient asynchronous getting of properties' values + * + * This is a high-level, convenience way of reading D-Bus properties' values that abstracts + * from the D-Bus message concept. + * + * Example of use: + * @code + * auto callback = [](std::optional err, const std::map>& properties){ ... }; + * auto props = object.getAllPropertiesAsync().onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); + * @endcode + * + * @throws sdbus::Error in case of failure + */ + [[nodiscard]] AsyncAllPropertiesGetter getAllPropertiesAsync(); + + /*! + * @brief Provides D-Bus connection used by the proxy + * + * @return Reference to the D-Bus connection + */ + [[nodiscard]] virtual sdbus::IConnection& getConnection() const = 0; + + /*! + * @brief Returns object path of the underlying DBus object + */ + [[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0; + + /*! + * @brief Provides access to the currently processed D-Bus message + * + * This method provides access to the currently processed incoming D-Bus message. + * "Currently processed" means that the registered callback handler(s) for that message + * are being invoked. This method is meant to be called from within a callback handler + * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is + * guaranteed to return a valid D-Bus message instance for which the handler is called. + * If called from other contexts/threads, it may return a valid or invalid message, depending + * on whether a message was processed or not at the time of the call. + * + * @return Currently processed D-Bus message + */ + [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; + + /*! + * @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls + * + * Unregistration is done automatically also in proxy's destructor. This method makes + * sense if, in the process of proxy removal, we need to make sure that callbacks + * are unregistered explicitly before the final destruction of the proxy instance. + * + * @throws sdbus::Error in case of failure + */ + virtual void unregister() = 0; + + public: // Lower-level, message-based API /*! * @brief Creates a method call message * @@ -325,73 +606,6 @@ namespace sdbus { , const std::chrono::duration<_Rep, _Period>& timeout , with_future_t ); - /*! - * @brief Calls method on the D-Bus object - * - * @param[in] methodName Name of the method - * @return A helper object for convenient invocation of the method - * - * This is a high-level, convenience way of calling D-Bus methods that abstracts - * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized - * in a message and D-Bus signatures automatically deduced from the provided native arguments - * and return values. - * - * Example of use: - * @code - * int result, a = ..., b = ...; - * MethodName multiply{"multiply"}; - * object_.callMethod(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] MethodInvoker callMethod(const MethodName& methodName); - - /*! - * @copydoc IProxy::callMethod(const MethodName&) - */ - [[nodiscard]] MethodInvoker callMethod(const std::string& methodName); - - /*! - * @copydoc IProxy::callMethod(const MethodName&) - */ - [[nodiscard]] MethodInvoker callMethod(const char* methodName); - - /*! - * @brief Calls method on the D-Bus object asynchronously - * - * @param[in] methodName Name of the method - * @return A helper object for convenient asynchronous invocation of the method - * - * This is a high-level, convenience way of calling D-Bus methods that abstracts - * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized - * in a message and D-Bus signatures automatically deduced from the provided native arguments - * and return values. - * - * Example of use: - * @code - * int a = ..., b = ...; - * MethodName multiply{"multiply"}; - * object_.callMethodAsync(multiply).onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result) - * { - * std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl; - * }); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] AsyncMethodInvoker callMethodAsync(const MethodName& methodName); - - /*! - * @copydoc IProxy::callMethodAsync(const MethodName&) - */ - [[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName); - - /*! - * @copydoc IProxy::callMethodAsync(const MethodName&) - */ - [[nodiscard]] AsyncMethodInvoker callMethodAsync(const char* methodName); - /*! * @brief Registers a handler for the desired signal emitted by the D-Bus object * @@ -433,220 +647,7 @@ namespace sdbus { , signal_handler signalHandler , return_slot_t ) = 0; - /*! - * @brief Registers signal handler for a given signal of the D-Bus object - * - * @param[in] signalName Name of the signal - * @return A helper object for convenient registration of the signal handler - * - * This is a high-level, convenience way of registering to D-Bus signals that abstracts - * from the D-Bus message concept. Signal arguments are automatically serialized - * in a message and D-Bus signatures automatically deduced from the parameters - * of the provided native signal callback. - * - * A signal can be subscribed to and unsubscribed from at any time during proxy - * lifetime. The subscription is active immediately after the call. - * - * Example of use: - * @code - * object_.uponSignal("stateChanged").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onStateChanged(arg1, arg2); }); - * sdbus::InterfaceName foo{"com.kistler.foo"}; - * sdbus::SignalName levelChanged{"levelChanged"}; - * object_.uponSignal(levelChanged).onInterface(foo).call([this](uint16_t level){ this->onLevelChanged(level); }); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] SignalSubscriber uponSignal(const SignalName& signalName); - - /*! - * @copydoc IProxy::uponSignal(const SignalName&) - */ - [[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName); - - /*! - * @copydoc IProxy::uponSignal(const SignalName&) - */ - [[nodiscard]] SignalSubscriber uponSignal(const char* signalName); - - /*! - * @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls - * - * Unregistration is done automatically also in proxy's destructor. This method makes - * sense if, in the process of proxy removal, we need to make sure that callbacks - * are unregistered explicitly before the final destruction of the proxy instance. - * - * @throws sdbus::Error in case of failure - */ - virtual void unregister() = 0; - - /*! - * @brief Gets value of a property of the D-Bus object - * - * @param[in] propertyName Name of the property - * @return A helper object for convenient getting of property value - * - * This is a high-level, convenience way of reading D-Bus property values that abstracts - * from the D-Bus message concept. sdbus::Variant is returned which shall then be converted - * to the real property type (implicit conversion is supported). - * - * Example of use: - * @code - * int state = object.getProperty("state").onInterface("com.kistler.foo"); - * sdbus::InterfaceName foo{"com.kistler.foo"}; - * sdbus::PropertyName level{"level"}; - * int level = object.getProperty(level).onInterface(foo); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] PropertyGetter getProperty(const PropertyName& propertyName); - - /*! - * @copydoc IProxy::getProperty(const PropertyName&) - */ - [[nodiscard]] PropertyGetter getProperty(std::string_view propertyName); - - /*! - * @brief Gets value of a property of the D-Bus object asynchronously - * - * @param[in] propertyName Name of the property - * @return A helper object for convenient asynchronous getting of property value - * - * This is a high-level, convenience way of reading D-Bus property values that abstracts - * from the D-Bus message concept. - * - * Example of use: - * @code - * std::future state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture(); - * auto callback = [](std::optional err, const sdbus::Variant& value){ ... }; - * object.getPropertyAsync("state").onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] AsyncPropertyGetter getPropertyAsync(const PropertyName& propertyName); - - /*! - * @copydoc IProxy::getPropertyAsync(const PropertyName&) - */ - [[nodiscard]] AsyncPropertyGetter getPropertyAsync(std::string_view propertyName); - - /*! - * @brief Sets value of a property of the D-Bus object - * - * @param[in] propertyName Name of the property - * @return A helper object for convenient setting of property value - * - * This is a high-level, convenience way of writing D-Bus property values that abstracts - * from the D-Bus message concept. - * Setting property value with NoReply flag is also supported. - * - * Example of use: - * @code - * int state = ...; - * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state); - * // Or we can just send the set message call without waiting for the reply - * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state, dont_expect_reply); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] PropertySetter setProperty(const PropertyName& propertyName); - - /*! - * @copydoc IProxy::setProperty(const PropertyName&) - */ - [[nodiscard]] PropertySetter setProperty(std::string_view propertyName); - - /*! - * @brief Sets value of a property of the D-Bus object asynchronously - * - * @param[in] propertyName Name of the property - * @return A helper object for convenient asynchronous setting of property value - * - * This is a high-level, convenience way of writing D-Bus property values that abstracts - * from the D-Bus message concept. - * - * Example of use: - * @code - * int state = ...; - * // We can wait until the set operation finishes by waiting on the future - * std::future res = object_.setPropertyAsync("state").onInterface("com.kistler.foo").toValue(state).getResultAsFuture(); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] AsyncPropertySetter setPropertyAsync(const PropertyName& propertyName); - - /*! - * @copydoc IProxy::setPropertyAsync(const PropertyName&) - */ - [[nodiscard]] AsyncPropertySetter setPropertyAsync(std::string_view propertyName); - - /*! - * @brief Gets values of all properties of the D-Bus object - * - * @return A helper object for convenient getting of properties' values - * - * This is a high-level, convenience way of reading D-Bus properties' values that abstracts - * from the D-Bus message concept. - * - * Example of use: - * @code - * auto props = object.getAllProperties().onInterface("com.kistler.foo"); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] AllPropertiesGetter getAllProperties(); - - /*! - * @brief Gets values of all properties of the D-Bus object asynchronously - * - * @return A helper object for convenient asynchronous getting of properties' values - * - * This is a high-level, convenience way of reading D-Bus properties' values that abstracts - * from the D-Bus message concept. - * - * Example of use: - * @code - * auto callback = [](std::optional err, const std::map>& properties){ ... }; - * auto props = object.getAllPropertiesAsync().onInterface("com.kistler.foo").uponReplyInvoke(std::move(callback)); - * @endcode - * - * @throws sdbus::Error in case of failure - */ - [[nodiscard]] AsyncAllPropertiesGetter getAllPropertiesAsync(); - - /*! - * @brief Provides D-Bus connection used by the proxy - * - * @return Reference to the D-Bus connection - */ - [[nodiscard]] virtual sdbus::IConnection& getConnection() const = 0; - - /*! - * @brief Returns object path of the underlying DBus object - */ - [[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0; - - /*! - * @brief Provides access to the currently processed D-Bus message - * - * This method provides access to the currently processed incoming D-Bus message. - * "Currently processed" means that the registered callback handler(s) for that message - * are being invoked. This method is meant to be called from within a callback handler - * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is - * guaranteed to return a valid D-Bus message instance for which the handler is called. - * If called from other contexts/threads, it may return a valid or invalid message, depending - * on whether a message was processed or not at the time of the call. - * - * @return Currently processed D-Bus message - */ - [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0; - - protected: + protected: // Internal API for efficiency reasons used by high-level API helper classes friend MethodInvoker; friend AsyncMethodInvoker; friend SignalSubscriber;