refactor: reorganize public API of main abstract classes (#437)

This commit is contained in:
Stanislav Angelovič
2024-04-24 08:48:39 +02:00
parent 0c75ad2b71
commit 26c6da11be
3 changed files with 468 additions and 418 deletions

View File

@ -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
*

View File

@ -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<VTableItem, std::decay_t<VTableItems>> && ...)> >
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<VTableItem> 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<VTableItem> vtable, return_slot_t) = 0;
[[nodiscard]] VTableAdder addVTable(std::vector<VTableItem> 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<VTableItem, std::decay_t<VTableItems>> && ...)> >
[[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<VTableItem> 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<VTableItem, std::decay_t<VTableItems>> && ...)> >
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<VTableItem> 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<VTableItem> 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;

View File

@ -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<sdbus::Variant> state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture();
* auto callback = [](std::optional<sdbus::Error> 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<void> 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<sdbus::Error> err, const std::map<PropertyName, Variant>>& 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<sdbus::Variant> state = object.getPropertyAsync("state").onInterface("com.kistler.foo").getResultAsFuture();
* auto callback = [](std::optional<sdbus::Error> 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<void> 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<sdbus::Error> err, const std::map<PropertyName, Variant>>& 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;