forked from Kistler-Group/sdbus-cpp
refactor: improve Object vtable registration (#388)
This improves the D-Bus object API registration/unregistration by making it more flexible, more dynamic, closer to sd-bus API design but still on high abstraction level, and -- most importantly -- less error-prone since no `finishRegistration()` call is needed anymore.
This commit is contained in:
@ -89,6 +89,8 @@ set(SDBUSCPP_HDR_SRCS
|
||||
set(SDBUSCPP_PUBLIC_HDRS
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/ConvenienceApiClasses.inl
|
||||
${SDBUSCPP_INCLUDE_DIR}/VTableItems.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/VTableItems.inl
|
||||
${SDBUSCPP_INCLUDE_DIR}/Error.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/IConnection.h
|
||||
${SDBUSCPP_INCLUDE_DIR}/AdaptorInterfaces.h
|
||||
|
@ -268,6 +268,7 @@ v2.0.0
|
||||
- `PollData::getRelativeTimeout()` return type was changed to `std::chrono::microseconds`.
|
||||
- `IConnection::processPendingRequest()` was renamed to `IConnection::processPendingEvent()`.
|
||||
- `Variant` constructor is now explicit.
|
||||
- Object D-Bus API registration is now done through `IObject::addVTable()` method. The registration is immediate; no `finishRegistration()` call is needed anymore.
|
||||
- Systemd of at least v238 is required to compile sdbus-c++
|
||||
- A proper fix for timeout handling
|
||||
- Fix for external event loops in which the event loop thread ID was not correctly initialized (now fixed and simplified by not needing the thread ID anymore)
|
||||
|
@ -306,16 +306,20 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Register D-Bus methods and signals on the concatenator object, and exports the object.
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenator->registerMethod(interfaceName, "concatenate", "ais", "s", &concatenate);
|
||||
concatenator->registerSignal(interfaceName, "concatenated", "s");
|
||||
concatenator->finishRegistration();
|
||||
concatenator->addVTable( sdbus::MethodVTableItem{"concatenate", "ais", {}, "s", {}, &concatenate, {}}
|
||||
, sdbus::SignalVTableItem{"concatenated", "s", {}, {}} )
|
||||
.forInterface(interfaceName);
|
||||
|
||||
// Run the I/O event loop on the bus connection.
|
||||
connection->enterEventLoop();
|
||||
}
|
||||
```
|
||||
|
||||
We establish a D-Bus system connection and request `org.sdbuscpp.concatenator` D-Bus name on it. This name will be used by D-Bus clients to find the service. We then create an object with path `/org/sdbuscpp/concatenator` on this connection. We register interfaces, its methods, signals that the object provides, and, through `finishRegistration()`, export the object (i.e., make it visible to clients) on the bus. Then we need to make sure to run the event loop upon the connection, which handles all incoming, outgoing and other requests.
|
||||
We establish a D-Bus system connection and request `org.sdbuscpp.concatenator` D-Bus name on it. This name will be used by D-Bus clients to find the service. We then create an object with path `/org/sdbuscpp/concatenator` on this connection. We add a so-called object vtable, where we declare and describe its D-Bus API, i.e. its interface, methods, signals, properties (if any) that the object provides. Then we need to make sure to run the event loop upon the connection, which handles all incoming, outgoing and other requests.
|
||||
|
||||
> **_Tip_:** There's also an overload of `addVTable()` method with `request_slot_t` tag parameter which returns a `Slot` object. The slot is a simple RAII-based handle of the associated vtable registration. As long as you keep the slot object, the vtable registration is active. When you let go of the slot, the vtable is automatically removed from the D-Bus object. This gives you the ability to implement "dynamic" D-Bus object API that is addable as well as removable at any time during object lifetime.
|
||||
|
||||
> **_Note_:** A D-Bus object can have any number of vtables attached to it. Even a D-Bus interface of an object can have multiple vtables attached to it.
|
||||
|
||||
The callback for any D-Bus object method on this level is any callable of signature `void(sdbus::MethodCall call)`. The `call` parameter is the incoming method call message. We need to deserialize our method input arguments from it. Then we can invoke the logic of the method and get the results. Then for the given `call`, we create a `reply` message, pack results into it and send it back to the caller through `send()`. (If we had a void-returning method, we'd just send an empty `reply` back.) We also fire a signal with the results. To do this, we need to create a signal message via object's `createSignal()`, serialize the results into it, and then send it out to subscribers by invoking object's `emitSignal()`.
|
||||
|
||||
@ -365,7 +369,7 @@ int main(int argc, char *argv[])
|
||||
assert(result == "1:2:3");
|
||||
}
|
||||
|
||||
// Invoke concatenate again, this time with no numbers and we shall get an error
|
||||
/ // Invoke concatenate again, this time with no numbers and we shall get an error
|
||||
{
|
||||
auto method = concatenatorProxy->createMethodCall(interfaceName, "concatenate");
|
||||
method << std::vector<int>() << separator;
|
||||
@ -526,15 +530,19 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Register D-Bus methods and signals on the concatenator object, and exports the object.
|
||||
const char* interfaceName = "org.sdbuscpp.Concatenator";
|
||||
concatenator->registerMethod("concatenate").onInterface(interfaceName).implementedAs(std::move(concatenate));
|
||||
concatenator->registerSignal("concatenated").onInterface(interfaceName).withParameters<std::string>();
|
||||
concatenator->finishRegistration();
|
||||
concatenator->addVTable( sdbus::registerMethod("concatenate").implementedAs(std::move(concatenate))
|
||||
, sdbus::registerSignal{"concatenated").withParameters<std::string>() )
|
||||
.forInterface(interfaceName);
|
||||
|
||||
// Run the loop on the connection.
|
||||
connection->enterEventLoop();
|
||||
}
|
||||
```
|
||||
|
||||
> **_Tip_:** There's also an overload of `addVTable(...).forInterface()` method with `request_slot_t` tag parameter which returns a `Slot` object. The slot is a simple RAII-based handle of the associated vtable registration. As long as you keep the slot object, the vtable registration is active. When you let go of the slot, the vtable is automatically removed from the D-Bus object. This gives you the ability to implement "dynamic" D-Bus object API that is addable as well as removable at any time during object lifetime.
|
||||
|
||||
> **_Note_:** A D-Bus object can have any number of vtables attached to it. Even a D-Bus interface of an object can have multiple vtables attached to it.
|
||||
|
||||
### Client side
|
||||
|
||||
```c++
|
||||
|
@ -21,14 +21,24 @@ public:
|
||||
|
||||
protected:
|
||||
Planet1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_.registerMethod("GetPopulation").onInterface(INTERFACE_NAME).withOutputParamNames("population").implementedAs([this](){ return this->GetPopulation(); });
|
||||
object_.registerProperty("Name").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Name(); });
|
||||
}
|
||||
|
||||
Planet1_adaptor(const Planet1_adaptor&) = delete;
|
||||
Planet1_adaptor& operator=(const Planet1_adaptor&) = delete;
|
||||
Planet1_adaptor(Planet1_adaptor&&) = default;
|
||||
Planet1_adaptor& operator=(Planet1_adaptor&&) = default;
|
||||
|
||||
~Planet1_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable( sdbus::registerMethod("GetPopulation").withOutputParamNames("population").implementedAs([this](){ return this->GetPopulation(); })
|
||||
, sdbus::registerProperty("Name").withGetter([this](){ return this->Name(); })
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint64_t GetPopulation() = 0;
|
||||
|
||||
@ -36,7 +46,7 @@ private:
|
||||
virtual std::string Name() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
@ -19,11 +19,11 @@
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
class ManagerAdaptor : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
|
||||
class ManagerAdaptor : public sdbus::AdaptorInterfaces<sdbus::ObjectManager_adaptor>
|
||||
{
|
||||
public:
|
||||
ManagerAdaptor(sdbus::IConnection& connection, std::string path)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
{
|
||||
registerAdaptor();
|
||||
}
|
||||
@ -34,15 +34,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class PlanetAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::ExampleManager::Planet1_adaptor,
|
||||
sdbus::ManagedObject_adaptor,
|
||||
sdbus::Properties_adaptor >
|
||||
class PlanetAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::ExampleManager::Planet1_adaptor
|
||||
, sdbus::ManagedObject_adaptor
|
||||
, sdbus::Properties_adaptor >
|
||||
{
|
||||
public:
|
||||
PlanetAdaptor(sdbus::IConnection& connection, std::string path, std::string name, uint64_t poulation)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
, m_name(std::move(name))
|
||||
, m_population(poulation)
|
||||
PlanetAdaptor(sdbus::IConnection& connection, std::string path, std::string name, uint64_t population)
|
||||
: AdaptorInterfaces(connection, std::move(path))
|
||||
, m_name(std::move(name))
|
||||
, m_population(population)
|
||||
{
|
||||
registerAdaptor();
|
||||
emitInterfacesAddedSignal({org::sdbuscpp::ExampleManager::Planet1_adaptor::INTERFACE_NAME});
|
||||
@ -105,4 +105,4 @@ int main()
|
||||
connection->releaseName("org.sdbuscpp.examplemanager");
|
||||
connection->leaveEventLoop();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -82,9 +82,10 @@ namespace sdbus {
|
||||
* adaptor-side interface classes representing interfaces (with methods, signals and properties)
|
||||
* of the D-Bus object.
|
||||
*
|
||||
* In the final adaptor class inherited from AdaptorInterfaces, it is necessary to finish
|
||||
* adaptor registration in class constructor (finishRegistration();`), and, conversely,
|
||||
* unregister the adaptor in class destructor (`unregister();`).
|
||||
* In the final adaptor class inherited from AdaptorInterfaces, one needs to make sure:
|
||||
* 1. to call `registerAdaptor();` in the class constructor, and, conversely,
|
||||
* 2. to call `unregisterAdaptor();` in the class destructor,
|
||||
* so that the object API vtable is registered and unregistered at the proper time.
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _Interfaces>
|
||||
@ -108,15 +109,15 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Finishes adaptor API registration and publishes the adaptor on the bus
|
||||
* @brief Adds object vtable (i.e. D-Bus API) definitions for all interfaces it implements
|
||||
*
|
||||
* This function must be called in the constructor of the final adaptor class that implements AdaptorInterfaces.
|
||||
*
|
||||
* For more information, see underlying @ref IObject::finishRegistration()
|
||||
* See also @ref IObject::addVTable()
|
||||
*/
|
||||
void registerAdaptor()
|
||||
{
|
||||
getObject().finishRegistration();
|
||||
(_Interfaces::registerAdaptor(), ...);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -132,12 +133,9 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
* @brief Returns reference to the underlying IObject instance
|
||||
*/
|
||||
const std::string& getObjectPath() const
|
||||
{
|
||||
return getObject().getObjectPath();
|
||||
}
|
||||
using ObjectHolder::getObject;
|
||||
|
||||
protected:
|
||||
using base_type = AdaptorInterfaces;
|
||||
|
@ -27,13 +27,13 @@
|
||||
#ifndef SDBUS_CXX_CONVENIENCEAPICLASSES_H_
|
||||
#define SDBUS_CXX_CONVENIENCEAPICLASSES_H_
|
||||
|
||||
#include <sdbus-c++/VTableItems.h>
|
||||
#include <sdbus-c++/Message.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <cstdint>
|
||||
@ -48,101 +48,16 @@ namespace sdbus {
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
class MethodRegistrator
|
||||
class VTableAdder
|
||||
{
|
||||
public:
|
||||
MethodRegistrator(IObject& object, std::string methodName);
|
||||
MethodRegistrator(MethodRegistrator&& other) = default;
|
||||
~MethodRegistrator() noexcept(false);
|
||||
|
||||
MethodRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename _Function> MethodRegistrator& implementedAs(_Function&& callback);
|
||||
MethodRegistrator& withInputParamNames(std::vector<std::string> paramNames);
|
||||
template <typename... _String> MethodRegistrator& withInputParamNames(_String... paramNames);
|
||||
MethodRegistrator& withOutputParamNames(std::vector<std::string> paramNames);
|
||||
template <typename... _String> MethodRegistrator& withOutputParamNames(_String... paramNames);
|
||||
MethodRegistrator& markAsDeprecated();
|
||||
MethodRegistrator& markAsPrivileged();
|
||||
MethodRegistrator& withNoReply();
|
||||
VTableAdder(IObject& object, std::vector<VTableItem> vtable);
|
||||
void forInterface(std::string interfaceName);
|
||||
[[nodiscard]] Slot forInterface(std::string interfaceName, request_slot_t);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
std::string methodName_;
|
||||
std::string interfaceName_;
|
||||
std::string inputSignature_;
|
||||
std::vector<std::string> inputParamNames_;
|
||||
std::string outputSignature_;
|
||||
std::vector<std::string> outputParamNames_;
|
||||
method_callback methodCallback_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
class SignalRegistrator
|
||||
{
|
||||
public:
|
||||
SignalRegistrator(IObject& object, std::string signalName);
|
||||
SignalRegistrator(SignalRegistrator&& other) = default;
|
||||
~SignalRegistrator() noexcept(false);
|
||||
|
||||
SignalRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename... _Args> SignalRegistrator& withParameters();
|
||||
template <typename... _Args> SignalRegistrator& withParameters(std::vector<std::string> paramNames);
|
||||
template <typename... _Args, typename... _String> SignalRegistrator& withParameters(_String... paramNames);
|
||||
SignalRegistrator& markAsDeprecated();
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
std::string signalName_;
|
||||
std::string interfaceName_;
|
||||
std::string signalSignature_;
|
||||
std::vector<std::string> paramNames_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when SignalRegistrator is constructed
|
||||
};
|
||||
|
||||
class PropertyRegistrator
|
||||
{
|
||||
public:
|
||||
PropertyRegistrator(IObject& object, const std::string& propertyName);
|
||||
PropertyRegistrator(PropertyRegistrator&& other) = default;
|
||||
~PropertyRegistrator() noexcept(false);
|
||||
|
||||
PropertyRegistrator& onInterface(std::string interfaceName);
|
||||
template <typename _Function> PropertyRegistrator& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyRegistrator& withSetter(_Function&& callback);
|
||||
PropertyRegistrator& markAsDeprecated();
|
||||
PropertyRegistrator& markAsPrivileged();
|
||||
PropertyRegistrator& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& propertyName_;
|
||||
std::string interfaceName_;
|
||||
std::string propertySignature_;
|
||||
property_get_callback getter_;
|
||||
property_set_callback setter_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
|
||||
};
|
||||
|
||||
class InterfaceFlagsSetter
|
||||
{
|
||||
public:
|
||||
InterfaceFlagsSetter(IObject& object, const std::string& interfaceName);
|
||||
InterfaceFlagsSetter(InterfaceFlagsSetter&& other) = default;
|
||||
~InterfaceFlagsSetter() noexcept(false);
|
||||
|
||||
InterfaceFlagsSetter& markAsDeprecated();
|
||||
InterfaceFlagsSetter& markAsPrivileged();
|
||||
InterfaceFlagsSetter& withNoReplyMethods();
|
||||
InterfaceFlagsSetter& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
private:
|
||||
IObject& object_;
|
||||
const std::string& interfaceName_;
|
||||
Flags flags_;
|
||||
int exceptions_{}; // Number of active exceptions when InterfaceFlagsSetter is constructed
|
||||
std::vector<VTableItem> vtable_;
|
||||
};
|
||||
|
||||
class SignalEmitter
|
||||
@ -313,6 +228,6 @@ namespace sdbus {
|
||||
const std::string* interfaceName_{};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace sdbus
|
||||
|
||||
#endif /* SDBUS_CXX_CONVENIENCEAPICLASSES_H_ */
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <exception>
|
||||
@ -41,374 +42,24 @@
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/*** ----------------- ***/
|
||||
/*** MethodRegistrator ***/
|
||||
/*** ----------------- ***/
|
||||
/*** ------------- ***/
|
||||
/*** VTableAdder ***/
|
||||
/*** ------------- ***/
|
||||
|
||||
inline MethodRegistrator::MethodRegistrator(IObject& object, std::string methodName)
|
||||
inline VTableAdder::VTableAdder(IObject& object, std::vector<VTableItem> vtable)
|
||||
: object_(object)
|
||||
, methodName_(std::move(methodName))
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
, vtable_(std::move(vtable))
|
||||
{
|
||||
}
|
||||
|
||||
inline MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the method if MethodRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
assert(methodCallback_); // implementedAs() must be placed/called prior to this function
|
||||
|
||||
// registerMethod() can throw. But as the MethodRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerMethod() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerMethod( interfaceName_
|
||||
, std::move(methodName_)
|
||||
, std::move(inputSignature_)
|
||||
, inputParamNames_
|
||||
, std::move(outputSignature_)
|
||||
, outputParamNames_
|
||||
, std::move(methodCallback_)
|
||||
, std::move(flags_));
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::onInterface(std::string interfaceName)
|
||||
inline void VTableAdder::forInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
object_.addVTable(std::move(interfaceName), std::move(vtable_));
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
MethodRegistrator& MethodRegistrator::implementedAs(_Function&& callback)
|
||||
inline Slot VTableAdder::forInterface(std::string interfaceName, request_slot_t)
|
||||
{
|
||||
inputSignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
methodCallback_ = [callback = std::forward<_Function>(callback)](MethodCall call)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<_Function> inputArgs;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple.
|
||||
call >> inputArgs;
|
||||
|
||||
if constexpr (!is_async_method_v<_Function>)
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
auto ret = sdbus::apply(callback, inputArgs);
|
||||
|
||||
// Store output arguments to the reply message and send it back.
|
||||
auto reply = call.createReply();
|
||||
reply << ret;
|
||||
reply.send();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple and with result object to be set later
|
||||
using AsyncResult = typename function_traits<_Function>::async_result_t;
|
||||
sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs));
|
||||
}
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withInputParamNames(std::vector<std::string> paramNames)
|
||||
{
|
||||
inputParamNames_ = std::move(paramNames);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodRegistrator& MethodRegistrator::withInputParamNames(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withInputParamNames({paramNames...});
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withOutputParamNames(std::vector<std::string> paramNames)
|
||||
{
|
||||
outputParamNames_ = std::move(paramNames);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodRegistrator& MethodRegistrator::withOutputParamNames(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withOutputParamNames({paramNames...});
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodRegistrator& MethodRegistrator::withNoReply()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** ----------------- ***/
|
||||
/*** SignalRegistrator ***/
|
||||
/*** ----------------- ***/
|
||||
|
||||
inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName)
|
||||
: object_(object)
|
||||
, signalName_(std::move(signalName))
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the signal if SignalRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
// registerSignal() can throw. But as the SignalRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerSignal() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerSignal( interfaceName_
|
||||
, std::move(signalName_)
|
||||
, std::move(signalSignature_)
|
||||
, paramNames_
|
||||
, std::move(flags_) );
|
||||
}
|
||||
|
||||
inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters()
|
||||
{
|
||||
signalSignature_ = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters(std::vector<std::string> paramNames)
|
||||
{
|
||||
paramNames_ = std::move(paramNames);
|
||||
|
||||
return withParameters<_Args...>();
|
||||
}
|
||||
|
||||
template <typename... _Args, typename... _String>
|
||||
inline SignalRegistrator& SignalRegistrator::withParameters(_String... paramNames)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "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<_Args...>({paramNames...});
|
||||
}
|
||||
|
||||
inline SignalRegistrator& SignalRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** ------------------- ***/
|
||||
/*** PropertyRegistrator ***/
|
||||
/*** ------------------- ***/
|
||||
|
||||
inline PropertyRegistrator::PropertyRegistrator(IObject& object, const std::string& propertyName)
|
||||
: object_(object)
|
||||
, propertyName_(propertyName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't register the property if PropertyRegistrator threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
// registerProperty() can throw. But as the PropertyRegistrator shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow registerProperty() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.registerProperty( interfaceName_
|
||||
, propertyName_
|
||||
, propertySignature_
|
||||
, std::move(getter_)
|
||||
, std::move(setter_)
|
||||
, flags_ );
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::onInterface(std::string interfaceName)
|
||||
{
|
||||
interfaceName_ = std::move(interfaceName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyRegistrator& PropertyRegistrator::withGetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_argument_count_v<_Function> == 0, "Property getter function must not take any arguments");
|
||||
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
|
||||
|
||||
if (propertySignature_.empty())
|
||||
propertySignature_ = signature_of_function_output_arguments<_Function>::str();
|
||||
|
||||
getter_ = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
|
||||
{
|
||||
// Get the propety value and serialize it into the pre-constructed reply message
|
||||
reply << callback();
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyRegistrator& PropertyRegistrator::withSetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_argument_count_v<_Function> == 1, "Property setter function must take one parameter - the property value");
|
||||
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
|
||||
|
||||
if (propertySignature_.empty())
|
||||
propertySignature_ = signature_of_function_input_arguments<_Function>::str();
|
||||
|
||||
setter_ = [callback = std::forward<_Function>(callback)](PropertySetCall call)
|
||||
{
|
||||
// Default-construct property value
|
||||
using property_type = function_argument_t<_Function, 0>;
|
||||
std::decay_t<property_type> property;
|
||||
|
||||
// Deserialize property value from the incoming call message
|
||||
call >> property;
|
||||
|
||||
// Invoke setter with the value
|
||||
callback(property);
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyRegistrator& PropertyRegistrator::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** InterfaceFlagsSetter ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
inline InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName)
|
||||
: object_(object)
|
||||
, interfaceName_(interfaceName)
|
||||
, exceptions_(std::uncaught_exceptions())
|
||||
{
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must
|
||||
{ // explicitly be allowed to throw
|
||||
// Don't set any flags if InterfaceFlagsSetter threw an exception in one of its methods
|
||||
if (std::uncaught_exceptions() != exceptions_)
|
||||
return;
|
||||
|
||||
// setInterfaceFlags() can throw. But as the InterfaceFlagsSetter shall always be used as an unnamed,
|
||||
// temporary object, i.e. not as a stack-allocated object, the double-exception situation
|
||||
// shall never happen. I.e. it should not happen that this destructor is directly called
|
||||
// in the stack-unwinding process of another flying exception (which would lead to immediate
|
||||
// termination). It can be called indirectly in the destructor of another object, but that's
|
||||
// fine and safe provided that the caller catches exceptions thrown from here.
|
||||
// Therefore, we can allow setInterfaceFlags() to throw even if we are in the destructor.
|
||||
// Bottomline is, to be on the safe side, the caller must take care of catching and reacting
|
||||
// to the exception thrown from here if the caller is a destructor itself.
|
||||
object_.setInterfaceFlags(interfaceName_, std::move(flags_));
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsDeprecated()
|
||||
{
|
||||
flags_.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsPrivileged()
|
||||
{
|
||||
flags_.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withNoReplyMethods()
|
||||
{
|
||||
flags_.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter& InterfaceFlagsSetter::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags_.set(behavior);
|
||||
|
||||
return *this;
|
||||
return object_.addVTable(std::move(interfaceName), std::move(vtable_), request_slot);
|
||||
}
|
||||
|
||||
/*** ------------- ***/
|
||||
@ -930,6 +581,6 @@ namespace sdbus {
|
||||
.getResultAsFuture<std::map<std::string, Variant>>();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace sdbus
|
||||
|
||||
#endif /* SDBUS_CPP_CONVENIENCEAPICLASSES_INL_ */
|
||||
|
@ -27,6 +27,7 @@
|
||||
#ifndef SDBUS_CXX_IOBJECT_H_
|
||||
#define SDBUS_CXX_IOBJECT_H_
|
||||
|
||||
#include <sdbus-c++/VTableItems.h>
|
||||
#include <sdbus-c++/ConvenienceApiClasses.h>
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
@ -62,144 +63,104 @@ namespace sdbus {
|
||||
virtual ~IObject() = default;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the method will belong to
|
||||
* @param[in] methodName Name of the method
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] methodCallback Callback that implements the body of the method
|
||||
* @param[in] flags D-Bus method flags (privileged, deprecated, or no reply)
|
||||
* @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 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 registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
template < typename... VTableItems
|
||||
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
|
||||
void addVTable(std::string interfaceName, VTableItems&&... items);
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the method will belong to
|
||||
* @param[in] methodName Name of the method
|
||||
* @param[in] inputSignature D-Bus signature of method input parameters
|
||||
* @param[in] inputNames Names of input parameters
|
||||
* @param[in] outputSignature D-Bus signature of method output parameters
|
||||
* @param[in] outputNames Names of output parameters
|
||||
* @param[in] methodCallback Callback that implements the body of the method
|
||||
* @param[in] flags D-Bus method flags (privileged, deprecated, or no reply)
|
||||
* @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
|
||||
*
|
||||
* Provided names of input and output parameters will be included in the introspection
|
||||
* description (given that at least version 242 of underlying libsystemd library is
|
||||
* used; otherwise, names of parameters are ignored). This usually helps better describe
|
||||
* the API to the introspector.
|
||||
* 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 registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, method_callback methodCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
virtual void addVTable(std::string interfaceName, std::vector<VTableItem> vtable) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will emit on D-Bus
|
||||
* @brief Adds a declaration of methods, properties and signals of the object at a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal will fall under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signature D-Bus signature of signal parameters
|
||||
* @param[in] flags D-Bus signal flags (deprecated)
|
||||
* @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
|
||||
* 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
|
||||
*/
|
||||
virtual void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags = {} ) = 0;
|
||||
virtual Slot addVTable(std::string interfaceName, std::vector<VTableItem> vtable, request_slot_t) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will emit on D-Bus
|
||||
* @brief A little more convenient overload of addVTable() above
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal will fall under
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signature D-Bus signature of signal parameters
|
||||
* @param[in] paramNames Names of parameters of the signal
|
||||
* @param[in] flags D-Bus signal flags (deprecated)
|
||||
* This version allows method chaining for a little safer and more readable VTable registration.
|
||||
*
|
||||
* Provided names of signal output parameters will be included in the introspection
|
||||
* description (given that at least version 242 of underlying libsystemd library is
|
||||
* used; otherwise, names of parameters are ignored). This usually helps better describe
|
||||
* the API to the introspector.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
* See addVTable() overloads above for detailed documentation.
|
||||
*/
|
||||
virtual void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags = {} ) = 0;
|
||||
template < typename... VTableItems
|
||||
, typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
|
||||
[[nodiscard]] VTableAdder addVTable(VTableItems&&... items);
|
||||
|
||||
/*!
|
||||
* @brief Registers read-only property that the object will provide on D-Bus
|
||||
* @brief A little more convenient overload of addVTable() above
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the property will fall under
|
||||
* @param[in] propertyName Name of the property
|
||||
* @param[in] signature D-Bus signature of property parameters
|
||||
* @param[in] getCallback Callback that implements the body of the property getter
|
||||
* @param[in] flags D-Bus property flags (deprecated, property update behavior)
|
||||
* This version allows method chaining for a little safer and more readable VTable registration.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
* See addVTable() overloads above for detailed documentation.
|
||||
*/
|
||||
virtual void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers read/write property that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the property will fall under
|
||||
* @param[in] propertyName Name of the property
|
||||
* @param[in] signature D-Bus signature of property parameters
|
||||
* @param[in] getCallback Callback that implements the body of the property getter
|
||||
* @param[in] setCallback Callback that implements the body of the property setter
|
||||
* @param[in] flags D-Bus property flags (deprecated, property update behavior)
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags = {} ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Sets flags for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @param[in] flags Flags to be set
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void setInterfaceFlags(const std::string& interfaceName, Flags flags) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Finishes object API registration and publishes the object on the bus
|
||||
*
|
||||
* The method exports all up to now registered methods, signals and properties on D-Bus.
|
||||
* Must be called after all methods, signals and properties have been registered.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void finishRegistration() = 0;
|
||||
[[nodiscard]] VTableAdder addVTable(std::vector<VTableItem> vtable);
|
||||
|
||||
/*!
|
||||
* @brief Unregisters object's API and removes object from the bus
|
||||
@ -276,10 +237,8 @@ namespace sdbus {
|
||||
* @brief Emits InterfacesAdded signal on this object path
|
||||
*
|
||||
* This emits an InterfacesAdded signal on this object path with explicitly provided list
|
||||
* of registered interfaces. As sdbus-c++ does currently not supported adding/removing
|
||||
* interfaces of an existing object at run time (an object has a fixed set of interfaces
|
||||
* registered by the time of invoking finishRegistration()), emitInterfacesAddedSignal(void)
|
||||
* is probably what you are looking for.
|
||||
* of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable
|
||||
* object interfaces and their vtables, so this method now makes more sense.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@ -300,10 +259,8 @@ namespace sdbus {
|
||||
* @brief Emits InterfacesRemoved signal on this object path
|
||||
*
|
||||
* This emits an InterfacesRemoved signal on the given path with explicitly provided list
|
||||
* of registered interfaces. As sdbus-c++ does currently not supported adding/removing
|
||||
* interfaces of an existing object at run time (an object has a fixed set of interfaces
|
||||
* registered by the time of invoking finishRegistration()), emitInterfacesRemovedSignal(void)
|
||||
* is probably what you are looking for.
|
||||
* of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable
|
||||
* object interfaces and their vtables, so this method now makes more sense.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
@ -340,81 +297,6 @@ namespace sdbus {
|
||||
*/
|
||||
virtual sdbus::IConnection& getConnection() const = 0;
|
||||
|
||||
/*!
|
||||
* @brief Registers method that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] methodName Name of the method
|
||||
* @return A helper object for convenient registration of the method
|
||||
*
|
||||
* This is a high-level, convenience way of registering 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 parameters and return type
|
||||
* of the provided native method implementation callback.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object.registerMethod("doFoo").onInterface("com.kistler.foo").implementedAs([this](int value){ return this->doFoo(value); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] MethodRegistrator registerMethod(const std::string& methodName);
|
||||
|
||||
/*!
|
||||
* @brief Registers signal that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A helper object for convenient registration of the signal
|
||||
*
|
||||
* This is a high-level, convenience way of registering D-Bus signals that abstracts
|
||||
* from the D-Bus message concept. Signal arguments are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native parameters.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object.registerSignal("paramChange").onInterface("com.kistler.foo").withParameters<std::map<int32_t, std::string>>();
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalRegistrator registerSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @brief Registers property that the object will provide on D-Bus
|
||||
*
|
||||
* @param[in] propertyName Name of the property
|
||||
* @return A helper object for convenient registration of the property
|
||||
*
|
||||
* This is a high-level, convenience way of registering D-Bus properties that abstracts
|
||||
* from the D-Bus message concept. Property arguments are automatically (de)serialized
|
||||
* in a message and D-Bus signatures automatically deduced from the provided native callbacks.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.registerProperty("state").onInterface("com.kistler.foo").withGetter([this](){ return this->state(); });
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] PropertyRegistrator registerProperty(const std::string& propertyName);
|
||||
|
||||
/*!
|
||||
* @brief Sets flags (annotations) for a given interface
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface whose flags will be set
|
||||
* @return A helper object for convenient setting of Interface flags
|
||||
*
|
||||
* This is a high-level, convenience alternative to the other setInterfaceFlags overload.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.setInterfaceFlags("com.kistler.foo").markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] InterfaceFlagsSetter setInterfaceFlags(const std::string& interfaceName);
|
||||
|
||||
/*!
|
||||
* @brief Emits signal on D-Bus
|
||||
*
|
||||
@ -459,31 +341,28 @@ namespace sdbus {
|
||||
|
||||
// Out-of-line member definitions
|
||||
|
||||
inline MethodRegistrator IObject::registerMethod(const std::string& methodName)
|
||||
{
|
||||
return MethodRegistrator(*this, methodName);
|
||||
}
|
||||
|
||||
inline SignalRegistrator IObject::registerSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalRegistrator(*this, signalName);
|
||||
}
|
||||
|
||||
inline PropertyRegistrator IObject::registerProperty(const std::string& propertyName)
|
||||
{
|
||||
return PropertyRegistrator(*this, propertyName);
|
||||
}
|
||||
|
||||
inline InterfaceFlagsSetter IObject::setInterfaceFlags(const std::string& interfaceName)
|
||||
{
|
||||
return InterfaceFlagsSetter(*this, interfaceName);
|
||||
}
|
||||
|
||||
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalEmitter(*this, signalName);
|
||||
}
|
||||
|
||||
template <typename... VTableItems, typename>
|
||||
void IObject::addVTable(std::string interfaceName, VTableItems&&... items)
|
||||
{
|
||||
addVTable(std::move(interfaceName), {std::forward<VTableItems>(items)...});
|
||||
}
|
||||
|
||||
template <typename... VTableItems, typename>
|
||||
VTableAdder IObject::addVTable(VTableItems&&... items)
|
||||
{
|
||||
return addVTable(std::vector<VTableItem>{std::forward<VTableItems>(items)...});
|
||||
}
|
||||
|
||||
inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)
|
||||
{
|
||||
return VTableAdder(*this, std::move(vtable));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates instance representing a D-Bus object
|
||||
*
|
||||
@ -506,6 +385,7 @@ namespace sdbus {
|
||||
|
||||
}
|
||||
|
||||
#include <sdbus-c++/VTableItems.inl>
|
||||
#include <sdbus-c++/ConvenienceApiClasses.inl>
|
||||
|
||||
#endif /* SDBUS_CXX_IOBJECT_H_ */
|
||||
|
@ -197,12 +197,9 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Returns object path of the underlying DBus object
|
||||
* @brief Returns reference to the underlying IProxy instance
|
||||
*/
|
||||
const std::string& getObjectPath() const
|
||||
{
|
||||
return getProxy().getObjectPath();
|
||||
}
|
||||
using ProxyObjectHolder::getProxy;
|
||||
|
||||
protected:
|
||||
using base_type = ProxyInterfaces;
|
||||
|
@ -251,8 +251,7 @@ namespace sdbus {
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
Properties_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
Properties_adaptor(sdbus::IObject& object) : object_(&object)
|
||||
{
|
||||
}
|
||||
|
||||
@ -263,6 +262,10 @@ namespace sdbus {
|
||||
|
||||
~Properties_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void emitPropertiesChangedSignal(const std::string& interfaceName, const std::vector<std::string>& properties)
|
||||
{
|
||||
@ -293,10 +296,8 @@ namespace sdbus {
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager";
|
||||
|
||||
protected:
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
explicit ObjectManager_adaptor(sdbus::IObject& object) : object_(&object)
|
||||
{
|
||||
object_->addObjectManager();
|
||||
}
|
||||
|
||||
ObjectManager_adaptor(const ObjectManager_adaptor&) = delete;
|
||||
@ -306,6 +307,11 @@ namespace sdbus {
|
||||
|
||||
~ObjectManager_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addObjectManager();
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IObject* object_;
|
||||
};
|
||||
@ -336,6 +342,10 @@ namespace sdbus {
|
||||
|
||||
~ManagedObject_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/*!
|
||||
* @brief Emits InterfacesAdded signal for this object path
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
|
||||
// Forward declarations
|
||||
namespace sdbus {
|
||||
@ -659,6 +660,15 @@ namespace sdbus {
|
||||
using future_return_t = typename future_return<_Args...>::type;
|
||||
|
||||
|
||||
// Credit: Piotr Skotnicki (https://stackoverflow.com/a/57639506)
|
||||
template <typename, typename>
|
||||
constexpr bool is_one_of_variants_types = false;
|
||||
|
||||
template <typename... _VariantTypes, typename _QueriedType>
|
||||
constexpr bool is_one_of_variants_types<std::variant<_VariantTypes...>, _QueriedType>
|
||||
= (std::is_same_v<_QueriedType, _VariantTypes> || ...);
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class _Function, class _Tuple, typename... _Args, std::size_t... _I>
|
||||
|
107
include/sdbus-c++/VTableItems.h
Normal file
107
include/sdbus-c++/VTableItems.h
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* (C) 2023 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableItems.h
|
||||
*
|
||||
* Created on: Dec 14, 2023
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CXX_VTABLEITEMS_H_
|
||||
#define SDBUS_CXX_VTABLEITEMS_H_
|
||||
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Flags.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
struct MethodVTableItem
|
||||
{
|
||||
template <typename _Function> MethodVTableItem& implementedAs(_Function&& callback);
|
||||
MethodVTableItem& withInputParamNames(std::vector<std::string> names);
|
||||
template <typename... _String> MethodVTableItem& withInputParamNames(_String... names);
|
||||
MethodVTableItem& withOutputParamNames(std::vector<std::string> names);
|
||||
template <typename... _String> MethodVTableItem& withOutputParamNames(_String... names);
|
||||
MethodVTableItem& markAsDeprecated();
|
||||
MethodVTableItem& markAsPrivileged();
|
||||
MethodVTableItem& withNoReply();
|
||||
|
||||
std::string name;
|
||||
std::string inputSignature;
|
||||
std::vector<std::string> inputParamNames;
|
||||
std::string outputSignature;
|
||||
std::vector<std::string> outputParamNames;
|
||||
method_callback callbackHandler;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
MethodVTableItem registerMethod(std::string methodName);
|
||||
|
||||
struct SignalVTableItem
|
||||
{
|
||||
template <typename... _Args> SignalVTableItem& withParameters();
|
||||
template <typename... _Args> SignalVTableItem& withParameters(std::vector<std::string> names);
|
||||
template <typename... _Args, typename... _String> SignalVTableItem& withParameters(_String... names);
|
||||
SignalVTableItem& markAsDeprecated();
|
||||
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::vector<std::string> paramNames;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
SignalVTableItem registerSignal(std::string signalName);
|
||||
|
||||
struct PropertyVTableItem
|
||||
{
|
||||
template <typename _Function> PropertyVTableItem& withGetter(_Function&& callback);
|
||||
template <typename _Function> PropertyVTableItem& withSetter(_Function&& callback);
|
||||
PropertyVTableItem& markAsDeprecated();
|
||||
PropertyVTableItem& markAsPrivileged();
|
||||
PropertyVTableItem& withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
std::string name;
|
||||
std::string signature;
|
||||
property_get_callback getter;
|
||||
property_set_callback setter;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
PropertyVTableItem registerProperty(std::string propertyName);
|
||||
|
||||
struct InterfaceFlagsVTableItem
|
||||
{
|
||||
InterfaceFlagsVTableItem& markAsDeprecated();
|
||||
InterfaceFlagsVTableItem& markAsPrivileged();
|
||||
InterfaceFlagsVTableItem& withNoReplyMethods();
|
||||
InterfaceFlagsVTableItem& withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior);
|
||||
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
InterfaceFlagsVTableItem setInterfaceFlags();
|
||||
|
||||
using VTableItem = std::variant<MethodVTableItem, SignalVTableItem, PropertyVTableItem, InterfaceFlagsVTableItem>;
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
#endif /* SDBUS_CXX_VTABLEITEMS_H_ */
|
285
include/sdbus-c++/VTableItems.inl
Normal file
285
include/sdbus-c++/VTableItems.inl
Normal file
@ -0,0 +1,285 @@
|
||||
/**
|
||||
* (C) 2023 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
|
||||
*
|
||||
* @file VTableItems.inl
|
||||
*
|
||||
* Created on: Dec 14, 2023
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDBUS_CPP_VTABLEITEMS_INL_
|
||||
#define SDBUS_CPP_VTABLEITEMS_INL_
|
||||
|
||||
#include <sdbus-c++/TypeTraits.h>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace sdbus {
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** Method VTable Item ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
template <typename _Function>
|
||||
MethodVTableItem& MethodVTableItem::implementedAs(_Function&& callback)
|
||||
{
|
||||
inputSignature = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature = signature_of_function_output_arguments<_Function>::str();
|
||||
callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the message.
|
||||
tuple_of_function_input_arg_types_t<_Function> inputArgs;
|
||||
|
||||
// Deserialize input arguments from the message into the tuple.
|
||||
call >> inputArgs;
|
||||
|
||||
if constexpr (!is_async_method_v<_Function>)
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
auto ret = sdbus::apply(callback, inputArgs);
|
||||
|
||||
// Store output arguments to the reply message and send it back.
|
||||
auto reply = call.createReply();
|
||||
reply << ret;
|
||||
reply.send();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invoke callback with input arguments from the tuple and with result object to be set later
|
||||
using AsyncResult = typename function_traits<_Function>::async_result_t;
|
||||
sdbus::apply(callback, AsyncResult{std::move(call)}, std::move(inputArgs));
|
||||
}
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withInputParamNames(std::vector<std::string> names)
|
||||
{
|
||||
inputParamNames = std::move(names);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodVTableItem& MethodVTableItem::withInputParamNames(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withInputParamNames({names...});
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(std::vector<std::string> names)
|
||||
{
|
||||
outputParamNames = std::move(names);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _String>
|
||||
inline MethodVTableItem& MethodVTableItem::withOutputParamNames(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "Parameter names must be (convertible to) strings");
|
||||
|
||||
return withOutputParamNames({names...});
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::markAsDeprecated()
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::markAsPrivileged()
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodVTableItem& MethodVTableItem::withNoReply()
|
||||
{
|
||||
flags.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline MethodVTableItem registerMethod(std::string methodName)
|
||||
{
|
||||
return {std::move(methodName), {}, {}, {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** Signal VTable Item ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters()
|
||||
{
|
||||
signature = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(std::vector<std::string> names)
|
||||
{
|
||||
paramNames = std::move(names);
|
||||
|
||||
return withParameters<_Args...>();
|
||||
}
|
||||
|
||||
template <typename... _Args, typename... _String>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters(_String... names)
|
||||
{
|
||||
static_assert(std::conjunction_v<std::is_convertible<_String, std::string>...>, "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<_Args...>({names...});
|
||||
}
|
||||
|
||||
inline SignalVTableItem& SignalVTableItem::markAsDeprecated()
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SignalVTableItem registerSignal(std::string signalName)
|
||||
{
|
||||
return {std::move(signalName), {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** -------------------- ***/
|
||||
/*** Property VTable Item ***/
|
||||
/*** -------------------- ***/
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyVTableItem& PropertyVTableItem::withGetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_argument_count_v<_Function> == 0, "Property getter function must not take any arguments");
|
||||
static_assert(!std::is_void<function_result_t<_Function>>::value, "Property getter function must return property value");
|
||||
|
||||
if (signature.empty())
|
||||
signature = signature_of_function_output_arguments<_Function>::str();
|
||||
|
||||
getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
|
||||
{
|
||||
// Get the propety value and serialize it into the pre-constructed reply message
|
||||
reply << callback();
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline PropertyVTableItem& PropertyVTableItem::withSetter(_Function&& callback)
|
||||
{
|
||||
static_assert(function_argument_count_v<_Function> == 1, "Property setter function must take one parameter - the property value");
|
||||
static_assert(std::is_void<function_result_t<_Function>>::value, "Property setter function must not return any value");
|
||||
|
||||
if (signature.empty())
|
||||
signature = signature_of_function_input_arguments<_Function>::str();
|
||||
|
||||
setter = [callback = std::forward<_Function>(callback)](PropertySetCall call)
|
||||
{
|
||||
// Default-construct property value
|
||||
using property_type = function_argument_t<_Function, 0>;
|
||||
std::decay_t<property_type> property;
|
||||
|
||||
// Deserialize property value from the incoming call message
|
||||
call >> property;
|
||||
|
||||
// Invoke setter with the value
|
||||
callback(property);
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::markAsDeprecated()
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::markAsPrivileged()
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyVTableItem& PropertyVTableItem::withUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PropertyVTableItem registerProperty(std::string propertyName)
|
||||
{
|
||||
return {std::move(propertyName), {}, {}, {}, {}};
|
||||
}
|
||||
|
||||
/*** --------------------------- ***/
|
||||
/*** Interface Flags VTable Item ***/
|
||||
/*** --------------------------- ***/
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsDeprecated()
|
||||
{
|
||||
flags.set(Flags::DEPRECATED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::markAsPrivileged()
|
||||
{
|
||||
flags.set(Flags::PRIVILEGED);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withNoReplyMethods()
|
||||
{
|
||||
flags.set(Flags::METHOD_NO_REPLY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem& InterfaceFlagsVTableItem::withPropertyUpdateBehavior(Flags::PropertyUpdateBehaviorFlags behavior)
|
||||
{
|
||||
flags.set(behavior);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline InterfaceFlagsVTableItem setInterfaceFlags()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace sdbus
|
||||
|
||||
#endif /* SDBUS_CPP_VTABLEITEMS_INL_ */
|
@ -470,7 +470,7 @@ Slot Connection::addObjectVTable( const std::string& objectPath
|
||||
{
|
||||
sd_bus_slot *slot{};
|
||||
|
||||
auto r = sdbus_->sd_bus_add_object_vtable(bus_.get()
|
||||
auto r = sdbus_->sd_bus_add_object_vtable( bus_.get()
|
||||
, &slot
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
@ -500,7 +500,7 @@ MethodCall Connection::createMethodCall( const std::string& destination
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_method_call(bus_.get()
|
||||
auto r = sdbus_->sd_bus_message_new_method_call( bus_.get()
|
||||
, &sdbusMsg
|
||||
, destination.empty() ? nullptr : destination.c_str()
|
||||
, objectPath.c_str()
|
||||
@ -518,7 +518,7 @@ Signal Connection::createSignal( const std::string& objectPath
|
||||
{
|
||||
sd_bus_message *sdbusMsg{};
|
||||
|
||||
auto r = sdbus_->sd_bus_message_new_signal(bus_.get()
|
||||
auto r = sdbus_->sd_bus_message_new_signal( bus_.get()
|
||||
, &sdbusMsg
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
@ -575,7 +575,7 @@ void Connection::emitPropertiesChangedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(propNames);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_properties_changed_strv(bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_properties_changed_strv( bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaceName.c_str()
|
||||
, propNames.empty() ? nullptr : &names[0] );
|
||||
@ -595,7 +595,7 @@ void Connection::emitInterfacesAddedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_added_strv(bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_added_strv( bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
@ -614,7 +614,7 @@ void Connection::emitInterfacesRemovedSignal( const std::string& objectPath
|
||||
{
|
||||
auto names = to_strv(interfaces);
|
||||
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv(bus_.get()
|
||||
auto r = sdbus_->sd_bus_emit_interfaces_removed_strv( bus_.get()
|
||||
, objectPath.c_str()
|
||||
, interfaces.empty() ? nullptr : &names[0] );
|
||||
|
||||
|
362
src/Object.cpp
362
src/Object.cpp
@ -47,129 +47,33 @@ Object::Object(sdbus::internal::IConnection& connection, std::string objectPath)
|
||||
SDBUS_CHECK_OBJECT_PATH(objectPath_);
|
||||
}
|
||||
|
||||
void Object::registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags )
|
||||
void Object::addVTable(std::string interfaceName, std::vector<VTableItem> vtable)
|
||||
{
|
||||
registerMethod( interfaceName
|
||||
, std::move(methodName)
|
||||
, std::move(inputSignature)
|
||||
, {}
|
||||
, std::move(outputSignature)
|
||||
, {}
|
||||
, std::move(methodCallback)
|
||||
, std::move(flags) );
|
||||
auto slot = Object::addVTable(std::move(interfaceName), std::move(vtable), request_slot);
|
||||
|
||||
vtables_.push_back(std::move(slot));
|
||||
}
|
||||
|
||||
void Object::registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, method_callback methodCallback
|
||||
, Flags flags )
|
||||
Slot Object::addVTable(std::string interfaceName, std::vector<VTableItem> vtable, request_slot_t)
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
SDBUS_CHECK_MEMBER_NAME(methodName);
|
||||
SDBUS_THROW_ERROR_IF(!methodCallback, "Invalid method callback provided", EINVAL);
|
||||
|
||||
auto& interface = getInterface(interfaceName);
|
||||
InterfaceData::MethodData methodData{ std::move(inputSignature)
|
||||
, std::move(outputSignature)
|
||||
, paramNamesToString(inputNames) + paramNamesToString(outputNames)
|
||||
, std::move(methodCallback)
|
||||
, std::move(flags) };
|
||||
auto inserted = interface.methods.emplace(std::move(methodName), std::move(methodData)).second;
|
||||
// 1st pass -- create vtable structure for internal sdbus-c++ purposes
|
||||
auto internalVTable = std::make_unique<VTable>(createInternalVTable(std::move(interfaceName), std::move(vtable)));
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register method: method already exists", EINVAL);
|
||||
}
|
||||
// 2nd pass -- from internal sdbus-c++ vtable, create vtable structure in format expected by underlying sd-bus library
|
||||
internalVTable->sdbusVTable = createInternalSdBusVTable(*internalVTable);
|
||||
|
||||
void Object::registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags )
|
||||
{
|
||||
registerSignal(interfaceName, std::move(signalName), std::move(signature), {}, std::move(flags));
|
||||
}
|
||||
// 3rd step -- register the vtable with sd-bus
|
||||
internalVTable->slot = connection_.addObjectVTable(objectPath_, internalVTable->interfaceName, &internalVTable->sdbusVTable[0], internalVTable.get());
|
||||
|
||||
void Object::registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
SDBUS_CHECK_MEMBER_NAME(signalName);
|
||||
|
||||
auto& interface = getInterface(interfaceName);
|
||||
|
||||
InterfaceData::SignalData signalData{std::move(signature), paramNamesToString(paramNames), std::move(flags)};
|
||||
auto inserted = interface.signals.emplace(std::move(signalName), std::move(signalData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal: signal already exists", EINVAL);
|
||||
}
|
||||
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags )
|
||||
{
|
||||
registerProperty( interfaceName
|
||||
, std::move(propertyName)
|
||||
, std::move(signature)
|
||||
, std::move(getCallback)
|
||||
, {}
|
||||
, std::move(flags) );
|
||||
}
|
||||
|
||||
void Object::registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags )
|
||||
{
|
||||
SDBUS_CHECK_INTERFACE_NAME(interfaceName);
|
||||
SDBUS_CHECK_MEMBER_NAME(propertyName);
|
||||
SDBUS_THROW_ERROR_IF(!getCallback && !setCallback, "Invalid property callbacks provided", EINVAL);
|
||||
|
||||
auto& interface = getInterface(interfaceName);
|
||||
|
||||
InterfaceData::PropertyData propertyData{ std::move(signature)
|
||||
, std::move(getCallback)
|
||||
, std::move(setCallback)
|
||||
, std::move(flags) };
|
||||
auto inserted = interface.properties.emplace(std::move(propertyName), std::move(propertyData)).second;
|
||||
|
||||
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register property: property already exists", EINVAL);
|
||||
}
|
||||
|
||||
void Object::setInterfaceFlags(const std::string& interfaceName, Flags flags)
|
||||
{
|
||||
auto& interface = getInterface(interfaceName);
|
||||
interface.flags = flags;
|
||||
}
|
||||
|
||||
void Object::finishRegistration()
|
||||
{
|
||||
for (auto& item : interfaces_)
|
||||
{
|
||||
const auto& interfaceName = item.first;
|
||||
auto& interfaceData = item.second;
|
||||
|
||||
const auto& vtable = createInterfaceVTable(interfaceData);
|
||||
activateInterfaceVTable(interfaceName, interfaceData, vtable);
|
||||
}
|
||||
// Return vtable wrapped in a Slot object
|
||||
return {internalVTable.release(), [](void *ptr){ delete static_cast<VTable*>(ptr); }};
|
||||
}
|
||||
|
||||
void Object::unregister()
|
||||
{
|
||||
interfaces_.clear();
|
||||
vtables_.clear();
|
||||
removeObjectManager();
|
||||
}
|
||||
|
||||
@ -245,81 +149,151 @@ Message Object::getCurrentlyProcessedMessage() const
|
||||
return connection_.getCurrentlyProcessedMessage();
|
||||
}
|
||||
|
||||
Object::InterfaceData& Object::getInterface(const std::string& interfaceName)
|
||||
Object::VTable Object::createInternalVTable(std::string interfaceName, std::vector<VTableItem> vtable)
|
||||
{
|
||||
return interfaces_.emplace(interfaceName, *this).first->second;
|
||||
}
|
||||
VTable internalVTable;
|
||||
|
||||
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
|
||||
{
|
||||
auto& vtable = interfaceData.vtable;
|
||||
assert(vtable.empty());
|
||||
internalVTable.interfaceName = std::move(interfaceName);
|
||||
|
||||
vtable.push_back(createVTableStartItem(interfaceData.flags.toSdBusInterfaceFlags()));
|
||||
registerMethodsToVTable(interfaceData, vtable);
|
||||
registerSignalsToVTable(interfaceData, vtable);
|
||||
registerPropertiesToVTable(interfaceData, vtable);
|
||||
vtable.push_back(createVTableEndItem());
|
||||
|
||||
return vtable;
|
||||
}
|
||||
|
||||
void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
for (const auto& item : interfaceData.methods)
|
||||
for (auto& vtableItem : vtable)
|
||||
{
|
||||
const auto& methodName = item.first;
|
||||
const auto& methodData = item.second;
|
||||
|
||||
vtable.push_back(createVTableMethodItem( methodName.c_str()
|
||||
, methodData.inputArgs.c_str()
|
||||
, methodData.outputArgs.c_str()
|
||||
, methodData.paramNames.c_str()
|
||||
, &Object::sdbus_method_callback
|
||||
, methodData.flags.toSdBusMethodFlags() ));
|
||||
std::visit( overload{ [&](InterfaceFlagsVTableItem&& interfaceFlags){ writeInterfaceFlagsToVTable(std::move(interfaceFlags), internalVTable); }
|
||||
, [&](MethodVTableItem&& method){ writeMethodRecordToVTable(std::move(method), internalVTable); }
|
||||
, [&](SignalVTableItem&& signal){ writeSignalRecordToVTable(std::move(signal), internalVTable); }
|
||||
, [&](PropertyVTableItem&& property){ writePropertyRecordToVTable(std::move(property), internalVTable); } }
|
||||
, std::move(vtableItem) );
|
||||
}
|
||||
|
||||
// Sort arrays so we can do fast searching for an item in sd-bus callback handlers
|
||||
std::sort(internalVTable.methods.begin(), internalVTable.methods.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
|
||||
std::sort(internalVTable.signals.begin(), internalVTable.signals.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
|
||||
std::sort(internalVTable.properties.begin(), internalVTable.properties.end(), [](const auto& a, const auto& b){ return a.name < b.name; });
|
||||
|
||||
internalVTable.object = this;
|
||||
|
||||
return internalVTable;
|
||||
}
|
||||
|
||||
void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
void Object::writeInterfaceFlagsToVTable(InterfaceFlagsVTableItem flags, VTable& vtable)
|
||||
{
|
||||
for (const auto& item : interfaceData.signals)
|
||||
vtable.interfaceFlags = std::move(flags.flags);
|
||||
}
|
||||
|
||||
void Object::writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(method.name);
|
||||
SDBUS_THROW_ERROR_IF(!method.callbackHandler, "Invalid method callback provided", EINVAL);
|
||||
|
||||
vtable.methods.push_back({ std::move(method.name)
|
||||
, std::move(method.inputSignature)
|
||||
, std::move(method.outputSignature)
|
||||
, paramNamesToString(method.inputParamNames) + paramNamesToString(method.outputParamNames)
|
||||
, std::move(method.callbackHandler)
|
||||
, std::move(method.flags) });
|
||||
}
|
||||
|
||||
void Object::writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(signal.name);
|
||||
|
||||
vtable.signals.push_back({ std::move(signal.name)
|
||||
, std::move(signal.signature)
|
||||
, paramNamesToString(signal.paramNames)
|
||||
, std::move(signal.flags) });
|
||||
}
|
||||
|
||||
void Object::writePropertyRecordToVTable(PropertyVTableItem property, VTable& vtable)
|
||||
{
|
||||
SDBUS_CHECK_MEMBER_NAME(property.name);
|
||||
SDBUS_THROW_ERROR_IF(!property.getter && !property.setter, "Invalid property callbacks provided", EINVAL);
|
||||
|
||||
vtable.properties.push_back({ std::move(property.name)
|
||||
, std::move(property.signature)
|
||||
, std::move(property.getter)
|
||||
, std::move(property.setter)
|
||||
, std::move(property.flags) });
|
||||
}
|
||||
|
||||
std::vector<sd_bus_vtable> Object::createInternalSdBusVTable(const VTable& vtable)
|
||||
{
|
||||
std::vector<sd_bus_vtable> sdbusVTable;
|
||||
|
||||
startSdBusVTable(vtable.interfaceFlags, sdbusVTable);
|
||||
for (const auto& methodItem : vtable.methods)
|
||||
writeMethodRecordToSdBusVTable(methodItem, sdbusVTable);
|
||||
for (const auto& signalItem : vtable.signals)
|
||||
writeSignalRecordToSdBusVTable(signalItem, sdbusVTable);
|
||||
for (const auto& propertyItem : vtable.properties)
|
||||
writePropertyRecordToSdBusVTable(propertyItem, sdbusVTable);
|
||||
finalizeSdBusVTable(sdbusVTable);
|
||||
|
||||
return sdbusVTable;
|
||||
}
|
||||
|
||||
void Object::startSdBusVTable(const Flags& interfaceFlags, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
auto vtableItem = createSdBusVTableStartItem(interfaceFlags.toSdBusInterfaceFlags());
|
||||
vtable.push_back(std::move(vtableItem));
|
||||
}
|
||||
|
||||
void Object::writeMethodRecordToSdBusVTable(const VTable::MethodItem& method, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
auto vtableItem = createSdBusVTableMethodItem( method.name.c_str()
|
||||
, method.inputArgs.c_str()
|
||||
, method.outputArgs.c_str()
|
||||
, method.paramNames.c_str()
|
||||
, &Object::sdbus_method_callback
|
||||
, method.flags.toSdBusMethodFlags() );
|
||||
vtable.push_back(std::move(vtableItem));
|
||||
}
|
||||
|
||||
void Object::writeSignalRecordToSdBusVTable(const VTable::SignalItem& signal, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
auto vtableItem = createSdBusVTableSignalItem( signal.name.c_str()
|
||||
, signal.signature.c_str()
|
||||
, signal.paramNames.c_str()
|
||||
, signal.flags.toSdBusSignalFlags() );
|
||||
vtable.push_back(std::move(vtableItem));
|
||||
}
|
||||
|
||||
void Object::writePropertyRecordToSdBusVTable(const VTable::PropertyItem& property, std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
auto vtableItem = !property.setCallback
|
||||
? createSdBusVTableReadOnlyPropertyItem( property.name.c_str()
|
||||
, property.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, property.flags.toSdBusPropertyFlags() )
|
||||
: createSdBusVTableWritablePropertyItem( property.name.c_str()
|
||||
, property.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, &Object::sdbus_property_set_callback
|
||||
, property.flags.toSdBusWritablePropertyFlags() );
|
||||
vtable.push_back(std::move(vtableItem));
|
||||
}
|
||||
|
||||
void Object::finalizeSdBusVTable(std::vector<sd_bus_vtable>& vtable)
|
||||
{
|
||||
vtable.push_back(createSdBusVTableEndItem());
|
||||
}
|
||||
|
||||
const Object::VTable::MethodItem* Object::findMethod(const VTable& vtable, const std::string& methodName)
|
||||
{
|
||||
auto it = std::lower_bound(vtable.methods.begin(), vtable.methods.end(), methodName, [](const auto& methodItem, const auto& methodName)
|
||||
{
|
||||
const auto& signalName = item.first;
|
||||
const auto& signalData = item.second;
|
||||
return methodItem.name < methodName;
|
||||
});
|
||||
|
||||
vtable.push_back(createVTableSignalItem( signalName.c_str()
|
||||
, signalData.signature.c_str()
|
||||
, signalData.paramNames.c_str()
|
||||
, signalData.flags.toSdBusSignalFlags() ));
|
||||
}
|
||||
return it != vtable.methods.end() && it->name == methodName ? &*it : nullptr;
|
||||
}
|
||||
|
||||
void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
|
||||
const Object::VTable::PropertyItem* Object::findProperty(const VTable& vtable, const std::string& propertyName)
|
||||
{
|
||||
for (const auto& item : interfaceData.properties)
|
||||
auto it = std::lower_bound(vtable.properties.begin(), vtable.properties.end(), propertyName, [](const auto& propertyItem, const auto& propertyName)
|
||||
{
|
||||
const auto& propertyName = item.first;
|
||||
const auto& propertyData = item.second;
|
||||
return propertyItem.name < propertyName;
|
||||
});
|
||||
|
||||
if (!propertyData.setCallback)
|
||||
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, propertyData.flags.toSdBusPropertyFlags() ));
|
||||
else
|
||||
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
|
||||
, propertyData.signature.c_str()
|
||||
, &Object::sdbus_property_get_callback
|
||||
, &Object::sdbus_property_set_callback
|
||||
, propertyData.flags.toSdBusWritablePropertyFlags() ));
|
||||
}
|
||||
}
|
||||
|
||||
void Object::activateInterfaceVTable( const std::string& interfaceName
|
||||
, InterfaceData& interfaceData
|
||||
, const std::vector<sd_bus_vtable>& vtable )
|
||||
{
|
||||
interfaceData.slot = connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], &interfaceData);
|
||||
return it != vtable.properties.end() && it->name == propertyName ? &*it : nullptr;
|
||||
}
|
||||
|
||||
std::string Object::paramNamesToString(const std::vector<std::string>& paramNames)
|
||||
@ -332,16 +306,17 @@ std::string Object::paramNamesToString(const std::vector<std::string>& paramName
|
||||
|
||||
int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
|
||||
{
|
||||
auto* interfaceData = static_cast<InterfaceData*>(userData);
|
||||
assert(interfaceData != nullptr);
|
||||
auto& object = interfaceData->object;
|
||||
auto* vtable = static_cast<VTable*>(userData);
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &object.connection_.getSdBusInterface());
|
||||
auto message = Message::Factory::create<MethodCall>(sdbusMessage, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
auto& callback = interfaceData->methods[message.getMemberName()].callback;
|
||||
assert(callback);
|
||||
const auto* methodItem = findMethod(*vtable, message.getMemberName());
|
||||
assert(methodItem != nullptr);
|
||||
assert(methodItem->callback);
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ callback(std::move(message)); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ methodItem->callback(std::move(message)); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
@ -354,21 +329,23 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
|
||||
, void *userData
|
||||
, sd_bus_error *retError )
|
||||
{
|
||||
auto* interfaceData = static_cast<InterfaceData*>(userData);
|
||||
assert(interfaceData != nullptr);
|
||||
auto& object = interfaceData->object;
|
||||
auto* vtable = static_cast<VTable*>(userData);
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
auto& callback = interfaceData->properties[property].getCallback;
|
||||
// Getter can be empty - the case of "write-only" property
|
||||
if (!callback)
|
||||
const auto* propertyItem = findProperty(*vtable, property);
|
||||
assert(propertyItem != nullptr);
|
||||
|
||||
// Getter may be empty - the case of "write-only" property
|
||||
if (!propertyItem->getCallback)
|
||||
{
|
||||
sd_bus_error_set(retError, "org.freedesktop.DBus.Error.Failed", "Cannot read property as it is write-only");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &object.connection_.getSdBusInterface());
|
||||
auto reply = Message::Factory::create<PropertyGetReply>(sdbusReply, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ callback(reply); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->getCallback(reply); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
@ -381,16 +358,17 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
|
||||
, void *userData
|
||||
, sd_bus_error *retError )
|
||||
{
|
||||
auto* interfaceData = static_cast<InterfaceData*>(userData);
|
||||
assert(interfaceData != nullptr);
|
||||
auto& object = interfaceData->object;
|
||||
auto* vtable = static_cast<VTable*>(userData);
|
||||
assert(vtable != nullptr);
|
||||
assert(vtable->object != nullptr);
|
||||
|
||||
auto& callback = interfaceData->properties[property].setCallback;
|
||||
assert(callback);
|
||||
const auto* propertyItem = findProperty(*vtable, property);
|
||||
assert(propertyItem != nullptr);
|
||||
assert(propertyItem->setCallback);
|
||||
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &object.connection_.getSdBusInterface());
|
||||
auto value = Message::Factory::create<PropertySetCall>(sdbusValue, &vtable->object->connection_.getSdBusInterface());
|
||||
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ callback(std::move(value)); }, retError);
|
||||
auto ok = invokeHandlerAndCatchErrors([&](){ propertyItem->setCallback(std::move(value)); }, retError);
|
||||
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
123
src/Object.h
123
src/Object.h
@ -31,7 +31,7 @@
|
||||
#include "IConnection.h"
|
||||
#include SDBUS_HEADER
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@ -45,46 +45,8 @@ namespace sdbus::internal {
|
||||
public:
|
||||
Object(sdbus::internal::IConnection& connection, std::string objectPath);
|
||||
|
||||
void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, std::string outputSignature
|
||||
, method_callback methodCallback
|
||||
, Flags flags ) override;
|
||||
void registerMethod( const std::string& interfaceName
|
||||
, std::string methodName
|
||||
, std::string inputSignature
|
||||
, const std::vector<std::string>& inputNames
|
||||
, std::string outputSignature
|
||||
, const std::vector<std::string>& outputNames
|
||||
, method_callback methodCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, Flags flags ) override;
|
||||
void registerSignal( const std::string& interfaceName
|
||||
, std::string signalName
|
||||
, std::string signature
|
||||
, const std::vector<std::string>& paramNames
|
||||
, Flags flags ) override;
|
||||
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, Flags flags ) override;
|
||||
void registerProperty( const std::string& interfaceName
|
||||
, std::string propertyName
|
||||
, std::string signature
|
||||
, property_get_callback getCallback
|
||||
, property_set_callback setCallback
|
||||
, Flags flags ) override;
|
||||
|
||||
void setInterfaceFlags(const std::string& interfaceName, Flags flags) override;
|
||||
|
||||
void finishRegistration() override;
|
||||
void addVTable(std::string interfaceName, std::vector<VTableItem> vtable) override;
|
||||
Slot addVTable(std::string interfaceName, std::vector<VTableItem> vtable, request_slot_t) override;
|
||||
void unregister() override;
|
||||
|
||||
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
|
||||
@ -105,55 +67,74 @@ namespace sdbus::internal {
|
||||
Message getCurrentlyProcessedMessage() const override;
|
||||
|
||||
private:
|
||||
using InterfaceName = std::string;
|
||||
struct InterfaceData
|
||||
// A vtable record comprising methods, signals, properties, flags.
|
||||
// Once created, it cannot be modified. Only new vtables records can be added.
|
||||
// An interface can have any number of vtables attached to it, not only one.
|
||||
struct VTable
|
||||
{
|
||||
InterfaceData(Object& object) : object(object) {}
|
||||
std::string interfaceName;
|
||||
Flags interfaceFlags;
|
||||
|
||||
using MethodName = std::string;
|
||||
struct MethodData
|
||||
struct MethodItem
|
||||
{
|
||||
const std::string inputArgs;
|
||||
const std::string outputArgs;
|
||||
const std::string paramNames;
|
||||
std::string name;
|
||||
std::string inputArgs;
|
||||
std::string outputArgs;
|
||||
std::string paramNames;
|
||||
method_callback callback;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<MethodName, MethodData> methods;
|
||||
using SignalName = std::string;
|
||||
struct SignalData
|
||||
// Array of method records sorted by method name
|
||||
std::vector<MethodItem> methods;
|
||||
|
||||
struct SignalItem
|
||||
{
|
||||
const std::string signature;
|
||||
const std::string paramNames;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::string paramNames;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<SignalName, SignalData> signals;
|
||||
using PropertyName = std::string;
|
||||
struct PropertyData
|
||||
// Array of signal records sorted by signal name
|
||||
std::vector<SignalItem> signals;
|
||||
|
||||
struct PropertyItem
|
||||
{
|
||||
const std::string signature;
|
||||
std::string name;
|
||||
std::string signature;
|
||||
property_get_callback getCallback;
|
||||
property_set_callback setCallback;
|
||||
Flags flags;
|
||||
};
|
||||
std::map<PropertyName, PropertyData> properties;
|
||||
std::vector<sd_bus_vtable> vtable;
|
||||
Flags flags;
|
||||
Object& object;
|
||||
// Array of signal records sorted by signal name
|
||||
std::vector<PropertyItem> properties;
|
||||
|
||||
// VTable structure in format required by sd-bus API
|
||||
std::vector<sd_bus_vtable> sdbusVTable;
|
||||
|
||||
// Back-reference to the owning object from sd-bus callback handlers
|
||||
Object* object{};
|
||||
|
||||
// This is intentionally the last member, because it must be destructed first,
|
||||
// releasing callbacks above before the callbacks themselves are destructed.
|
||||
Slot slot;
|
||||
};
|
||||
|
||||
InterfaceData& getInterface(const std::string& interfaceName);
|
||||
static const std::vector<sd_bus_vtable>& createInterfaceVTable(InterfaceData& interfaceData);
|
||||
static void registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
|
||||
static void registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
|
||||
static void registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
|
||||
void activateInterfaceVTable( const std::string& interfaceName
|
||||
, InterfaceData& interfaceData
|
||||
, const std::vector<sd_bus_vtable>& vtable );
|
||||
VTable createInternalVTable(std::string interfaceName, std::vector<VTableItem> vtable);
|
||||
void writeInterfaceFlagsToVTable(InterfaceFlagsVTableItem flags, VTable& vtable);
|
||||
void writeMethodRecordToVTable(MethodVTableItem method, VTable& vtable);
|
||||
void writeSignalRecordToVTable(SignalVTableItem signal, VTable& vtable);
|
||||
void writePropertyRecordToVTable(PropertyVTableItem property, VTable& vtable);
|
||||
|
||||
std::vector<sd_bus_vtable> createInternalSdBusVTable(const VTable& vtable);
|
||||
static void startSdBusVTable(const Flags& interfaceFlags, std::vector<sd_bus_vtable>& vtable);
|
||||
static void writeMethodRecordToSdBusVTable(const VTable::MethodItem& method, std::vector<sd_bus_vtable>& vtable);
|
||||
static void writeSignalRecordToSdBusVTable(const VTable::SignalItem& signal, std::vector<sd_bus_vtable>& vtable);
|
||||
static void writePropertyRecordToSdBusVTable(const VTable::PropertyItem& property, std::vector<sd_bus_vtable>& vtable);
|
||||
static void finalizeSdBusVTable(std::vector<sd_bus_vtable>& vtable);
|
||||
|
||||
static const VTable::MethodItem* findMethod(const VTable& vtable, const std::string& methodName);
|
||||
static const VTable::PropertyItem* findProperty(const VTable& vtable, const std::string& propertyName);
|
||||
|
||||
static std::string paramNamesToString(const std::vector<std::string>& paramNames);
|
||||
|
||||
static int sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
|
||||
@ -175,7 +156,7 @@ namespace sdbus::internal {
|
||||
private:
|
||||
sdbus::internal::IConnection& connection_;
|
||||
std::string objectPath_;
|
||||
std::map<InterfaceName, InterfaceData> interfaces_;
|
||||
std::vector<Slot> vtables_;
|
||||
Slot objectManagerSlot_;
|
||||
};
|
||||
|
||||
|
@ -27,18 +27,18 @@
|
||||
#include "VTableUtils.h"
|
||||
#include SDBUS_HEADER
|
||||
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags)
|
||||
sd_bus_vtable createSdBusVTableStartItem(uint64_t flags)
|
||||
{
|
||||
struct sd_bus_vtable vtableStart = SD_BUS_VTABLE_START(flags);
|
||||
return vtableStart;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags )
|
||||
sd_bus_vtable createSdBusVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags )
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
// We have to expand macro SD_BUS_METHOD_WITH_NAMES manually here, because the macro expects literal char strings
|
||||
@ -65,10 +65,10 @@ sd_bus_vtable createVTableMethodItem( const char *member
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags )
|
||||
sd_bus_vtable createSdBusVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags )
|
||||
{
|
||||
#if LIBSYSTEMD_VERSION>=242
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_SIGNAL_WITH_NAMES(member, signature, outnames, flags);
|
||||
@ -79,26 +79,26 @@ sd_bus_vtable createVTableSignalItem( const char *member
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags )
|
||||
sd_bus_vtable createSdBusVTableReadOnlyPropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_PROPERTY(member, signature, getter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags )
|
||||
sd_bus_vtable createSdBusVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags )
|
||||
{
|
||||
struct sd_bus_vtable vtableItem = SD_BUS_WRITABLE_PROPERTY(member, signature, getter, setter, 0, flags);
|
||||
return vtableItem;
|
||||
}
|
||||
|
||||
sd_bus_vtable createVTableEndItem()
|
||||
sd_bus_vtable createSdBusVTableEndItem()
|
||||
{
|
||||
struct sd_bus_vtable vtableEnd = SD_BUS_VTABLE_END;
|
||||
return vtableEnd;
|
||||
|
@ -34,27 +34,27 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sd_bus_vtable createVTableStartItem(uint64_t flags);
|
||||
sd_bus_vtable createVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createVTableEndItem();
|
||||
sd_bus_vtable createSdBusVTableStartItem(uint64_t flags);
|
||||
sd_bus_vtable createSdBusVTableMethodItem( const char *member
|
||||
, const char *signature
|
||||
, const char *result
|
||||
, const char *paramNames
|
||||
, sd_bus_message_handler_t handler
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createSdBusVTableSignalItem( const char *member
|
||||
, const char *signature
|
||||
, const char *outnames
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createSdBusVTableReadOnlyPropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createSdBusVTableWritablePropertyItem( const char *member
|
||||
, const char *signature
|
||||
, sd_bus_property_get_t getter
|
||||
, sd_bus_property_set_t setter
|
||||
, uint64_t flags );
|
||||
sd_bus_vtable createSdBusVTableEndItem();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -81,7 +81,6 @@ TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccesfully)
|
||||
auto vectorRes = this->m_proxy->getInts16FromStruct(a);
|
||||
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0
|
||||
|
||||
|
||||
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
|
||||
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE}
|
||||
};
|
||||
@ -288,3 +287,34 @@ TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
|
||||
|
||||
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanRegisterAdditionalVTableDynamicallyAtAnyTime)
|
||||
{
|
||||
auto& object = this->m_adaptor->getObject();
|
||||
auto vtableSlot = object.addVTable( "org.sdbuscpp.integrationtests2"
|
||||
, { sdbus::registerMethod("add").implementedAs([](const int64_t& a, const double& b){ return a + b; })
|
||||
, sdbus::registerMethod("subtract").implementedAs([](const int& a, const int& b){ return a - b; })}
|
||||
, sdbus::request_slot );
|
||||
|
||||
// The new remote vtable is registered as long as we keep vtableSlot, so remote method calls now should pass
|
||||
auto proxy = sdbus::createProxy(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
int result{};
|
||||
proxy->callMethod("subtract").onInterface("org.sdbuscpp.integrationtests2").withArguments(10, 2).storeResultsTo(result);
|
||||
|
||||
ASSERT_THAT(result, Eq(8));
|
||||
}
|
||||
|
||||
TYPED_TEST(SdbusTestObject, CanUnregisterAdditionallyRegisteredVTableAtAnyTime)
|
||||
{
|
||||
auto& object = this->m_adaptor->getObject();
|
||||
|
||||
auto vtableSlot = object.addVTable( "org.sdbuscpp.integrationtests2"
|
||||
, { sdbus::registerMethod("add").implementedAs([](const int64_t& a, const double& b){ return a + b; })
|
||||
, sdbus::registerMethod("subtract").implementedAs([](const int& a, const int& b){ return a - b; })}
|
||||
, sdbus::request_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...
|
||||
auto proxy = sdbus::createProxy(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);
|
||||
ASSERT_THROW(proxy->callMethod("subtract").onInterface("org.sdbuscpp.integrationtests2").withArguments(10, 2), sdbus::Error);
|
||||
}
|
||||
|
@ -22,34 +22,6 @@ protected:
|
||||
integrationtests_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
|
||||
object_->registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
|
||||
object_->registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
|
||||
object_->registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
|
||||
object_->registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
|
||||
object_->registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
|
||||
object_->registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
|
||||
object_->registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const std::variant<int32_t, double, std::string>& variant){ return this->processVariant(variant); });
|
||||
object_->registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
|
||||
object_->registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
|
||||
object_->registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
|
||||
object_->registerMethod("sumArrayItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1){ return this->sumArrayItems(arg0, arg1); });
|
||||
object_->registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
|
||||
object_->registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
|
||||
object_->registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
|
||||
object_->registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
|
||||
object_->registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
|
||||
object_->registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getComplex(); }).markAsDeprecated();
|
||||
object_->registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); });
|
||||
object_->registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwErrorWithNoReply(); }).withNoReply();
|
||||
object_->registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
|
||||
object_->registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
|
||||
object_->registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
|
||||
object_->registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
|
||||
object_->registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
|
||||
object_->registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
|
||||
object_->registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
|
||||
object_->registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
|
||||
}
|
||||
|
||||
integrationtests_adaptor(const integrationtests_adaptor&) = delete;
|
||||
@ -59,6 +31,39 @@ protected:
|
||||
|
||||
~integrationtests_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable( sdbus::setInterfaceFlags().markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL)
|
||||
, sdbus::registerMethod("noArgNoReturn").implementedAs([this](){ return this->noArgNoReturn(); })
|
||||
, sdbus::registerMethod("getInt").withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); })
|
||||
, sdbus::registerMethod("getTuple").withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); })
|
||||
, sdbus::registerMethod("multiply").withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); })
|
||||
, sdbus::registerMethod("multiplyWithNoReply").withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply()
|
||||
, sdbus::registerMethod("getInts16FromStruct").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); })
|
||||
, sdbus::registerMethod("processVariant").withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const std::variant<int32_t, double, std::string>& variant){ return this->processVariant(variant); })
|
||||
, sdbus::registerMethod("getMapOfVariants").withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); })
|
||||
, sdbus::registerMethod("getStructInStruct").withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); })
|
||||
, sdbus::registerMethod("sumStructItems").withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); })
|
||||
, sdbus::registerMethod("sumArrayItems").withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::array<uint64_t, 3>& arg1){ return this->sumArrayItems(arg0, arg1); })
|
||||
, sdbus::registerMethod("doOperation").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); })
|
||||
, sdbus::registerMethod("doOperationAsync").withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); })
|
||||
, sdbus::registerMethod("getSignature").withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); })
|
||||
, sdbus::registerMethod("getObjPath").withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); })
|
||||
, sdbus::registerMethod("getUnixFd").withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); })
|
||||
, sdbus::registerMethod("getComplex").withOutputParamNames("arg0").implementedAs([this](){ return this->getComplex(); }).markAsDeprecated()
|
||||
, sdbus::registerMethod("throwError").implementedAs([this](){ return this->throwError(); })
|
||||
, sdbus::registerMethod("throwErrorWithNoReply").implementedAs([this](){ return this->throwErrorWithNoReply(); }).withNoReply()
|
||||
, sdbus::registerMethod("doPrivilegedStuff").implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged()
|
||||
, sdbus::registerMethod("emitTwoSimpleSignals").implementedAs([this](){ return this->emitTwoSimpleSignals(); })
|
||||
, sdbus::registerSignal("simpleSignal").markAsDeprecated()
|
||||
, sdbus::registerSignal("signalWithMap").withParameters<std::map<int32_t, std::string>>("aMap")
|
||||
, sdbus::registerSignal("signalWithVariant").withParameters<sdbus::Variant>("aVariant")
|
||||
, sdbus::registerProperty("action").withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL)
|
||||
, sdbus::registerProperty("blocking").withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); })
|
||||
, sdbus::registerProperty("state").withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE)
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
public:
|
||||
void emitSimpleSignal()
|
||||
{
|
||||
|
@ -22,9 +22,6 @@ protected:
|
||||
perftests_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("sendDataSignals").onInterface(INTERFACE_NAME).withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); });
|
||||
object_->registerMethod("concatenateTwoStrings").onInterface(INTERFACE_NAME).withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); });
|
||||
object_->registerSignal("dataSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("data");
|
||||
}
|
||||
|
||||
perftests_adaptor(const perftests_adaptor&) = delete;
|
||||
@ -34,6 +31,14 @@ protected:
|
||||
|
||||
~perftests_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable( sdbus::registerMethod("sendDataSignals").withInputParamNames("numberOfSignals", "signalMsgSize").implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); })
|
||||
, sdbus::registerMethod("concatenateTwoStrings").withInputParamNames("string1", "string2").withOutputParamNames("result").implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); })
|
||||
, sdbus::registerSignal("dataSignal").withParameters<std::string>("data")
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
public:
|
||||
void emitDataSignal(const std::string& data)
|
||||
{
|
||||
|
@ -24,7 +24,6 @@ protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
@ -34,6 +33,11 @@ protected:
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
|
@ -23,8 +23,6 @@ protected:
|
||||
concatenator_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("concatenate").onInterface(INTERFACE_NAME).withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); });
|
||||
object_->registerSignal("concatenatedSignal").onInterface(INTERFACE_NAME).withParameters<std::string>("concatenatedString");
|
||||
}
|
||||
|
||||
concatenator_adaptor(const concatenator_adaptor&) = delete;
|
||||
@ -34,6 +32,13 @@ protected:
|
||||
|
||||
~concatenator_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable( sdbus::registerMethod("concatenate").withInputParamNames("params").withOutputParamNames("result").implementedAs([this](sdbus::Result<std::string>&& result, std::map<std::string, sdbus::Variant> params){ this->concatenate(std::move(result), std::move(params)); })
|
||||
, sdbus::registerSignal("concatenatedSignal").withParameters<std::string>("concatenatedString")
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
public:
|
||||
void emitConcatenatedSignal(const std::string& concatenatedString)
|
||||
{
|
||||
|
@ -24,7 +24,6 @@ protected:
|
||||
thermometer_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("getCurrentTemperature").onInterface(INTERFACE_NAME).withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); });
|
||||
}
|
||||
|
||||
thermometer_adaptor(const thermometer_adaptor&) = delete;
|
||||
@ -34,6 +33,11 @@ protected:
|
||||
|
||||
~thermometer_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable(sdbus::registerMethod("getCurrentTemperature").withOutputParamNames("result").implementedAs([this](){ return this->getCurrentTemperature(); })).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual uint32_t getCurrentTemperature() = 0;
|
||||
|
||||
@ -58,8 +62,6 @@ protected:
|
||||
factory_adaptor(sdbus::IObject& object)
|
||||
: object_(&object)
|
||||
{
|
||||
object_->registerMethod("createDelegateObject").onInterface(INTERFACE_NAME).withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); });
|
||||
object_->registerMethod("destroyDelegateObject").onInterface(INTERFACE_NAME).withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply();
|
||||
}
|
||||
|
||||
factory_adaptor(const factory_adaptor&) = delete;
|
||||
@ -69,6 +71,13 @@ protected:
|
||||
|
||||
~factory_adaptor() = default;
|
||||
|
||||
void registerAdaptor()
|
||||
{
|
||||
object_->addVTable( sdbus::registerMethod("createDelegateObject").withOutputParamNames("delegate").implementedAs([this](sdbus::Result<sdbus::ObjectPath>&& result){ this->createDelegateObject(std::move(result)); })
|
||||
, sdbus::registerMethod("destroyDelegateObject").withInputParamNames("delegate").implementedAs([this](sdbus::Result<>&& result, sdbus::ObjectPath delegate){ this->destroyDelegateObject(std::move(result), std::move(delegate)); }).withNoReply()
|
||||
).forInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void createDelegateObject(sdbus::Result<sdbus::ObjectPath>&& result) = 0;
|
||||
virtual void destroyDelegateObject(sdbus::Result<>&& result, sdbus::ObjectPath delegate) = 0;
|
||||
|
@ -85,7 +85,17 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
<< tab << "static constexpr const char* INTERFACE_NAME = \"" << ifaceName << "\";" << endl << endl
|
||||
<< "protected:" << endl
|
||||
<< tab << className << "(sdbus::IObject& object)" << endl
|
||||
<< tab << tab << ": object_(&object)" << endl;
|
||||
<< tab << tab << ": object_(&object)" << endl
|
||||
<< tab << "{" << endl
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
Nodes methods = interface["method"];
|
||||
Nodes signals = interface["signal"];
|
||||
@ -111,34 +121,29 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
if(!annotationRegistration.empty())
|
||||
{
|
||||
std::stringstream str;
|
||||
str << tab << tab << "object_->setInterfaceFlags(INTERFACE_NAME)" << annotationRegistration << ";" << endl;
|
||||
str << "sdbus::setInterfaceFlags()" << annotationRegistration << ";";
|
||||
annotationRegistration = str.str();
|
||||
}
|
||||
|
||||
std::string methodRegistration, methodDeclaration;
|
||||
std::tie(methodRegistration, methodDeclaration) = processMethods(methods);
|
||||
std::vector<std::string> methodRegistrations;
|
||||
std::string methodDeclaration;
|
||||
std::tie(methodRegistrations, methodDeclaration) = processMethods(methods);
|
||||
|
||||
std::string signalRegistration, signalMethods;
|
||||
std::tie(signalRegistration, signalMethods) = processSignals(signals);
|
||||
std::vector<std::string> signalRegistrations;
|
||||
std::string signalMethods;
|
||||
std::tie(signalRegistrations, signalMethods) = processSignals(signals);
|
||||
|
||||
std::string propertyRegistration, propertyAccessorDeclaration;
|
||||
std::tie(propertyRegistration, propertyAccessorDeclaration) = processProperties(properties);
|
||||
std::vector<std::string> propertyRegistrations;
|
||||
std::string propertyAccessorDeclaration;
|
||||
std::tie(propertyRegistrations, propertyAccessorDeclaration) = processProperties(properties);
|
||||
|
||||
body << tab << "{" << endl
|
||||
<< annotationRegistration
|
||||
<< methodRegistration
|
||||
<< signalRegistration
|
||||
<< propertyRegistration
|
||||
auto vtableRegistration = createVTableRegistration(annotationRegistration, methodRegistrations, signalRegistrations, propertyRegistrations);
|
||||
|
||||
body << tab << "void registerAdaptor()" << endl
|
||||
<< tab << "{" << endl
|
||||
<< vtableRegistration << endl
|
||||
<< tab << "}" << endl << endl;
|
||||
|
||||
// Rule of Five
|
||||
body << tab << className << "(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "& operator=(const " << className << "&) = delete;" << endl;
|
||||
body << tab << className << "(" << className << "&&) = default;" << endl;
|
||||
body << tab << className << "& operator=(" << className << "&&) = default;" << endl << endl;
|
||||
|
||||
body << tab << "~" << className << "() = default;" << endl << endl;
|
||||
|
||||
if (!signalMethods.empty())
|
||||
{
|
||||
body << "public:" << endl << signalMethods;
|
||||
@ -163,12 +168,16 @@ std::string AdaptorGenerator::processInterface(Node& interface) const
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Nodes& methods) const
|
||||
std::tuple<std::vector<std::string>, std::string> AdaptorGenerator::processMethods(const Nodes& methods) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
std::ostringstream declarationSS;
|
||||
|
||||
std::vector<std::string> methodRegistrations;
|
||||
|
||||
for (const auto& method : methods)
|
||||
{
|
||||
std::ostringstream registrationSS;
|
||||
|
||||
auto methodName = method->get("name");
|
||||
auto methodNameSafe = mangle_name(methodName);
|
||||
|
||||
@ -217,9 +226,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
registrationSS << tab << tab << "object_->registerMethod(\""
|
||||
registrationSS << "sdbus::registerMethod(\""
|
||||
<< methodName << "\")"
|
||||
<< ".onInterface(INTERFACE_NAME)"
|
||||
<< (!argStringsStr.empty() ? (".withInputParamNames(" + argStringsStr + ")") : "")
|
||||
<< (!outArgStringsStr.empty() ? (".withOutputParamNames(" + outArgStringsStr + ")") : "")
|
||||
<< ".implementedAs("
|
||||
@ -229,7 +237,9 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
<< "){ " << (async ? "" : "return ") << "this->" << methodNameSafe << "("
|
||||
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
|
||||
<< argStr << "); })"
|
||||
<< annotationRegistration << ";" << endl;
|
||||
<< annotationRegistration;
|
||||
|
||||
methodRegistrations.push_back(registrationSS.str());
|
||||
|
||||
declarationSS << tab
|
||||
<< "virtual "
|
||||
@ -241,16 +251,20 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
|
||||
<< ") = 0;" << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
return std::make_tuple(methodRegistrations, declarationSS.str());
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Nodes& signals) const
|
||||
std::tuple<std::vector<std::string>, std::string> AdaptorGenerator::processSignals(const Nodes& signals) const
|
||||
{
|
||||
std::ostringstream signalRegistrationSS, signalMethodSS;
|
||||
std::ostringstream signalMethodSS;
|
||||
|
||||
std::vector<std::string> signalRegistrations;
|
||||
|
||||
for (const auto& signal : signals)
|
||||
{
|
||||
std::stringstream signalRegistrationSS;
|
||||
|
||||
auto name = signal->get("name");
|
||||
|
||||
auto annotations = getAnnotations(*signal);
|
||||
@ -272,9 +286,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
std::string argStr, argTypeStr, typeStr, argStringsStr;
|
||||
std::tie(argStr, argTypeStr, typeStr, argStringsStr) = argsToNamesAndTypes(args);
|
||||
|
||||
signalRegistrationSS << tab << tab
|
||||
<< "object_->registerSignal(\"" << name << "\")"
|
||||
".onInterface(INTERFACE_NAME)";
|
||||
signalRegistrationSS << "sdbus::registerSignal(\"" << name << "\")";
|
||||
|
||||
if (args.size() > 0)
|
||||
{
|
||||
@ -282,7 +294,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
}
|
||||
|
||||
signalRegistrationSS << annotationRegistration;
|
||||
signalRegistrationSS << ";" << endl;
|
||||
|
||||
signalRegistrations.push_back(signalRegistrationSS.str());
|
||||
|
||||
auto nameWithCapFirstLetter = name;
|
||||
nameWithCapFirstLetter[0] = std::toupper(nameWithCapFirstLetter[0]);
|
||||
@ -302,16 +315,20 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
|
||||
<< tab << "}" << endl << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(signalRegistrationSS.str(), signalMethodSS.str());
|
||||
return std::make_tuple(signalRegistrations, signalMethodSS.str());
|
||||
}
|
||||
|
||||
|
||||
std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const Nodes& properties) const
|
||||
std::tuple<std::vector<std::string>, std::string> AdaptorGenerator::processProperties(const Nodes& properties) const
|
||||
{
|
||||
std::ostringstream registrationSS, declarationSS;
|
||||
std::ostringstream declarationSS;
|
||||
|
||||
std::vector<std::string> propertyRegistrations;
|
||||
|
||||
for (const auto& property : properties)
|
||||
{
|
||||
std::ostringstream registrationSS;
|
||||
|
||||
auto propertyName = property->get("name");
|
||||
auto propertyNameSafe = mangle_name(propertyName);
|
||||
auto propertyAccess = property->get("access");
|
||||
@ -339,9 +356,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
<< "Option '" << annotationName << "' not allowed or supported in this context! Option ignored..." << std::endl;
|
||||
}
|
||||
|
||||
registrationSS << tab << tab << "object_->registerProperty(\""
|
||||
<< propertyName << "\")"
|
||||
<< ".onInterface(INTERFACE_NAME)";
|
||||
registrationSS << "sdbus::registerProperty(\""
|
||||
<< propertyName << "\")";
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
{
|
||||
@ -356,7 +372,8 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
}
|
||||
|
||||
registrationSS << annotationRegistration;
|
||||
registrationSS << ";" << endl;
|
||||
|
||||
propertyRegistrations.push_back(registrationSS.str());
|
||||
|
||||
if (propertyAccess == "read" || propertyAccess == "readwrite")
|
||||
declarationSS << tab << "virtual " << propertyType << " " << propertyNameSafe << "() = 0;" << endl;
|
||||
@ -364,7 +381,38 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
|
||||
declarationSS << tab << "virtual void " << propertyNameSafe << "(" << propertyTypeArg << ") = 0;" << endl;
|
||||
}
|
||||
|
||||
return std::make_tuple(registrationSS.str(), declarationSS.str());
|
||||
return std::make_tuple(propertyRegistrations, declarationSS.str());
|
||||
}
|
||||
|
||||
std::string AdaptorGenerator::createVTableRegistration(const std::string& annotationRegistration,
|
||||
const std::vector<std::string>& methodRegistrations,
|
||||
const std::vector<std::string>& signalRegistrations,
|
||||
const std::vector<std::string>& propertyRegistrations) const
|
||||
{
|
||||
std::vector<std::string> allRegistrations;
|
||||
if (!annotationRegistration.empty())
|
||||
allRegistrations.push_back(annotationRegistration);
|
||||
allRegistrations.insert(allRegistrations.end(), methodRegistrations.begin(), methodRegistrations.end());
|
||||
allRegistrations.insert(allRegistrations.end(), signalRegistrations.begin(), signalRegistrations.end());
|
||||
allRegistrations.insert(allRegistrations.end(), propertyRegistrations.begin(), propertyRegistrations.end());
|
||||
|
||||
if (allRegistrations.empty())
|
||||
return {};
|
||||
|
||||
std::ostringstream registrationSS;
|
||||
if (allRegistrations.size() == 1)
|
||||
{
|
||||
registrationSS << tab << tab << "object_->addVTable(" << allRegistrations[0] << ").forInterface(INTERFACE_NAME);";
|
||||
}
|
||||
else
|
||||
{
|
||||
registrationSS << tab << tab << "object_->addVTable( " << allRegistrations[0] << endl;
|
||||
for (size_t i = 1; i < allRegistrations.size(); ++i)
|
||||
registrationSS << tab << tab << " , " << allRegistrations[i] << endl;
|
||||
registrationSS << tab << tab << " ).forInterface(INTERFACE_NAME);";
|
||||
}
|
||||
|
||||
return registrationSS.str();
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> AdaptorGenerator::getAnnotations( sdbuscpp::xml::Node& node) const
|
||||
|
@ -59,21 +59,26 @@ private:
|
||||
* @param methods
|
||||
* @return tuple: registration of methods, declaration of abstract methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processMethods(const sdbuscpp::xml::Nodes& methods) const;
|
||||
std::tuple<std::vector<std::string>, std::string> processMethods(const sdbuscpp::xml::Nodes& methods) const;
|
||||
|
||||
/**
|
||||
* Generate source code for signals
|
||||
* @param signals
|
||||
* @return tuple: registration of signals, definition of signal methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processSignals(const sdbuscpp::xml::Nodes& signals) const;
|
||||
std::tuple<std::vector<std::string>, std::string> processSignals(const sdbuscpp::xml::Nodes& signals) const;
|
||||
|
||||
/**
|
||||
* Generate source code for properties
|
||||
* @param properties
|
||||
* @return tuple: registration of properties, declaration of property accessor virtual methods
|
||||
*/
|
||||
std::tuple<std::string, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
|
||||
std::tuple<std::vector<std::string>, std::string> processProperties(const sdbuscpp::xml::Nodes& properties) const;
|
||||
|
||||
std::string createVTableRegistration(const std::string& annotationRegistration,
|
||||
const std::vector<std::string>& methodRegistrations,
|
||||
const std::vector<std::string>& signalRegistrations,
|
||||
const std::vector<std::string>& propertyRegistrations) const;
|
||||
|
||||
/**
|
||||
* Get annotations listed for a given node
|
||||
|
Reference in New Issue
Block a user