Introduce sdbus-c++ v0.2.3

This commit is contained in:
Stanislav Angelovic
2017-11-27 14:13:55 +01:00
parent 32db1c22e3
commit 35f725a053
69 changed files with 9223 additions and 2 deletions
+23
View File
@@ -0,0 +1,23 @@
# Distribution
# Headers will be installed to $(includedir)/sdbus-c++ directory
HEADER_DIR = sdbus-c++
libsdbuscppdir = $(includedir)/$(HEADER_DIR)
libsdbuscpp_HEADERS = \
$(HEADER_DIR)/ConvenienceClasses.h \
$(HEADER_DIR)/ConvenienceClasses.inl \
$(HEADER_DIR)/Error.h \
$(HEADER_DIR)/IConnection.h \
$(HEADER_DIR)/Interfaces.h \
$(HEADER_DIR)/Introspection.h \
$(HEADER_DIR)/IObject.h \
$(HEADER_DIR)/IObjectProxy.h \
$(HEADER_DIR)/Message.h \
$(HEADER_DIR)/Types.h \
$(HEADER_DIR)/TypeTraits.h \
$(HEADER_DIR)/sdbus-c++.h
EXTRA_DIST = ($libsdbuscpp_HEADERS)
DISTCLEANFILES = Makefile Makefile.in
+169
View File
@@ -0,0 +1,169 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file ConvenienceClasses.h
*
* Created on: Jan 19, 2017
* 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_CONVENIENCECLASSES_H_
#define SDBUS_CXX_CONVENIENCECLASSES_H_
#include <sdbus-c++/Message.h>
#include <string>
// Forward declarations
namespace sdbus {
class IObject;
class IObjectProxy;
class Variant;
}
namespace sdbus {
class MethodRegistrator
{
public:
MethodRegistrator(IObject& object, const std::string& methodName);
MethodRegistrator& onInterface(const std::string& interfaceName);
template <typename _Function> void implementedAs(_Function&& callback);
private:
IObject& object_;
const std::string& methodName_;
std::string interfaceName_;
};
class SignalRegistrator
{
public:
SignalRegistrator(IObject& object, const std::string& signalName);
SignalRegistrator(SignalRegistrator&& other) = default;
SignalRegistrator& operator=(SignalRegistrator&& other) = default;
~SignalRegistrator() noexcept(false);
SignalRegistrator& onInterface(std::string interfaceName);
template <typename... _Args> void withParameters();
private:
IObject& object_;
const std::string& signalName_;
std::string interfaceName_;
std::string signalSignature_;
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& operator=(PropertyRegistrator&& other) = default;
~PropertyRegistrator() noexcept(false);
PropertyRegistrator& onInterface(const std::string& interfaceName);
template <typename _Function> PropertyRegistrator& withGetter(_Function&& callback);
template <typename _Function> PropertyRegistrator& withSetter(_Function&& callback);
private:
IObject& object_;
const std::string& propertyName_;
std::string interfaceName_;
std::string propertySignature_;
property_get_callback getter_;
property_set_callback setter_;
int exceptions_{}; // Number of active exceptions when PropertyRegistrator is constructed
};
class SignalEmitter
{
public:
SignalEmitter(IObject& object, const std::string& signalName);
SignalEmitter(SignalEmitter&& other) = default;
SignalEmitter& operator=(SignalEmitter&& other) = default;
~SignalEmitter() noexcept(false);
SignalEmitter& onInterface(const std::string& interfaceName);
template <typename... _Args> void withArguments(_Args&&... args);
private:
IObject& object_;
const std::string& signalName_;
Message signal_;
int exceptions_{}; // Number of active exceptions when SignalEmitter is constructed
};
class MethodInvoker
{
public:
MethodInvoker(IObjectProxy& objectProxy, const std::string& methodName);
MethodInvoker(MethodInvoker&& other) = default;
MethodInvoker& operator=(MethodInvoker&& other) = default;
~MethodInvoker() noexcept(false);
MethodInvoker& onInterface(const std::string& interfaceName);
template <typename... _Args> MethodInvoker& withArguments(_Args&&... args);
template <typename... _Args> void storeResultsTo(_Args&... args);
private:
IObjectProxy& objectProxy_;
const std::string& methodName_;
Message method_;
int exceptions_{}; // Number of active exceptions when MethodInvoker is constructed
bool methodCalled_{};
};
class SignalSubscriber
{
public:
SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName);
SignalSubscriber& onInterface(const std::string& interfaceName);
template <typename _Function> void call(_Function&& callback);
private:
IObjectProxy& objectProxy_;
std::string signalName_;
std::string interfaceName_;
};
class PropertyGetter
{
public:
PropertyGetter(IObjectProxy& objectProxy, const std::string& propertyName);
sdbus::Variant onInterface(const std::string& interfaceName);
private:
IObjectProxy& objectProxy_;
std::string propertyName_;
};
class PropertySetter
{
public:
PropertySetter(IObjectProxy& objectProxy, const std::string& propertyName);
PropertySetter& onInterface(const std::string& interfaceName);
template <typename _Value> void toValue(const _Value& value);
private:
IObjectProxy& objectProxy_;
const std::string& propertyName_;
std::string interfaceName_;
};
}
#endif /* SDBUS_CXX_CONVENIENCECLASSES_H_ */
+401
View File
@@ -0,0 +1,401 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file ConvenienceClasses.inl
*
* Created on: Dec 19, 2016
* 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_CONVENIENCECLASSES_INL_
#define SDBUS_CPP_CONVENIENCECLASSES_INL_
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IObjectProxy.h>
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Types.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Error.h>
#include <string>
#include <tuple>
/*#include <exception>*/
namespace sdbus {
inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName)
: object_(object)
, methodName_(methodName)
{
}
inline MethodRegistrator& MethodRegistrator::onInterface(const std::string& interfaceName)
{
interfaceName_ = interfaceName;
return *this;
}
template <typename _Function>
inline void MethodRegistrator::implementedAs(_Function&& callback)
{
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL);
object_.registerMethod( interfaceName_
, methodName_
, signature_of_function_input_arguments<_Function>::str()
, signature_of_function_output_arguments<_Function>::str()
, [callback = std::forward<_Function>(callback)](Message& msg, Message& reply)
{
// 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
msg >> inputArgs;
// Invoke callback with input arguments from the tuple.
// For callbacks returning a non-void value, `apply' also returns that value.
// For callbacks returning void, `apply' returns an empty tuple.
auto ret = apply(callback, inputArgs); // We don't yet have C++17's std::apply :-(
// The return value is stored to the reply message.
// In case of void functions, ret is an empty tuple and thus nothing is stored.
reply << ret;
});
}
// Moved into the library to isolate from C++17 dependency
/*
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;
if (interfaceName_.empty())
throw sdbus::Exception("DBus interface not specified when registering a DBus signal");
// 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_, signalName_, signalSignature_);
}
*/
inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName)
{
interfaceName_ = std::move(interfaceName);
return *this;
}
template <typename... _Args>
inline void SignalRegistrator::withParameters()
{
signalSignature_ = signature_of_function_input_arguments<void(_Args...)>::str();
}
// Moved into the library to isolate from C++17 dependency
/*
inline PropertyRegistrator::PropertyRegistrator(IObject& object, std::string propertyName)
: object_(object)
, propertyName_(std::move(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;
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus property", EINVAL);
// 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( std::move(interfaceName_)
, std::move(propertyName_)
, std::move(propertySignature_)
, std::move(getter_)
, std::move(setter_) );
}
*/
inline PropertyRegistrator& PropertyRegistrator::onInterface(const std::string& interfaceName)
{
interfaceName_ = interfaceName;
return *this;
}
template <typename _Function>
inline PropertyRegistrator& PropertyRegistrator::withGetter(_Function&& callback)
{
static_assert(function_traits<_Function>::arity == 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)](Message& msg)
{
// Get the propety value and serialize it into the message
msg << callback();
};
return *this;
}
template <typename _Function>
inline PropertyRegistrator& PropertyRegistrator::withSetter(_Function&& callback)
{
static_assert(function_traits<_Function>::arity == 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)](Message& msg)
{
// Default-construct property value
using property_type = function_argument_t<_Function, 0>;
std::decay_t<property_type> property;
// Deserialize property value from the message
msg >> property;
// Invoke setter with the value
callback(property);
};
return *this;
}
// Moved into the library to isolate from C++17 dependency
/*
inline SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName)
: object_(object)
, signalName_(signalName)
, exceptions_(std::uncaught_exceptions())
{
}
inline SignalEmitter::~SignalEmitter() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't emit the signal if SignalEmitter threw an exception in one of its methods
if (std::uncaught_exceptions() != exceptions_)
return;
if (!signal_.isValid())
throw sdbus::Exception("DBus interface not specified when emitting a DBus signal");
// emitSignal() can throw. But as the SignalEmitter 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 emitSignal() 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_.emitSignal(signal_);
}
*/
inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName)
{
signal_ = object_.createSignal(interfaceName, signalName_);
return *this;
}
template <typename... _Args>
inline void SignalEmitter::withArguments(_Args&&... args)
{
SDBUS_THROW_ERROR_IF(!signal_.isValid(), "DBus interface not specified when emitting a DBus signal", EINVAL);
detail::serialize_pack(signal_, std::forward<_Args>(args)...);
}
// Moved into the library to isolate from C++17 dependency
/*
inline MethodInvoker::MethodInvoker(IObjectProxy& objectProxy, const std::string& methodName)
: objectProxy_(objectProxy)
, methodName_(methodName)
, exceptions_(std::uncaught_exceptions())
{
}
inline MethodInvoker::~MethodInvoker() noexcept(false) // since C++11, destructors must
{ // explicitly be allowed to throw
// Don't call the method if it has been called already or if MethodInvoker
// threw an exception in one of its methods
if (methodCalled_ || std::uncaught_exceptions() != exceptions_)
return;
if (!method_.isValid())
throw sdbus::Exception("DBus interface not specified when calling a DBus method");
// callMethod() can throw. But as the MethodInvoker 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 callMethod() 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.
objectProxy_.callMethod(method_);
}
*/
inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName)
{
method_ = objectProxy_.createMethodCall(interfaceName, methodName_);
return *this;
}
template <typename... _Args>
inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args)
{
SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
detail::serialize_pack(method_, std::forward<_Args>(args)...);
return *this;
}
template <typename... _Args>
inline void MethodInvoker::storeResultsTo(_Args&... args)
{
SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL);
auto reply = objectProxy_.callMethod(method_);
methodCalled_ = true;
detail::deserialize_pack(reply, args...);
}
inline SignalSubscriber::SignalSubscriber(IObjectProxy& objectProxy, const std::string& signalName)
: objectProxy_(objectProxy)
, signalName_(signalName)
{
}
inline SignalSubscriber& SignalSubscriber::onInterface(const std::string& interfaceName)
{
interfaceName_ = interfaceName;
return *this;
}
template <typename _Function>
inline void SignalSubscriber::call(_Function&& callback)
{
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when subscribing to a signal", EINVAL);
objectProxy_.registerSignalHandler( interfaceName_
, signalName_
, [callback = std::forward<_Function>(callback)](Message& signal)
{
// Create a tuple of callback input arguments' types, which will be used
// as a storage for the argument values deserialized from the signal message.
tuple_of_function_input_arg_types_t<_Function> signalArgs;
// Deserialize input arguments from the signal message into the tuple
signal >> signalArgs;
// Invoke callback with input arguments from the tuple.
apply(callback, signalArgs); // We don't yet have C++17's std::apply :-(
});
}
inline PropertyGetter::PropertyGetter(IObjectProxy& objectProxy, const std::string& propertyName)
: objectProxy_(objectProxy)
, propertyName_(propertyName)
{
}
inline sdbus::Variant PropertyGetter::onInterface(const std::string& interfaceName)
{
sdbus::Variant var;
objectProxy_
.callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName, propertyName_)
.storeResultsTo(var);
return var;
}
inline PropertySetter::PropertySetter(IObjectProxy& objectProxy, const std::string& propertyName)
: objectProxy_(objectProxy)
, propertyName_(propertyName)
{
}
inline PropertySetter& PropertySetter::onInterface(const std::string& interfaceName)
{
interfaceName_ = interfaceName;
return *this;
}
template <typename _Value>
inline void PropertySetter::toValue(const _Value& value)
{
SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting a property", EINVAL);
objectProxy_
.callMethod("Set")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments(interfaceName_, propertyName_, sdbus::Variant{value});
}
}
#endif /* SDBUS_CPP_CONVENIENCECLASSES_INL_ */
+76
View File
@@ -0,0 +1,76 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file ConvenienceClasses.h
*
* Created on: Nov 8, 2016
* 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_ERROR_H_
#define SDBUS_CXX_ERROR_H_
#include <stdexcept>
namespace sdbus {
/********************************************//**
* @class Error
*
* Represents a common sdbus-c++ exception.
*
***********************************************/
class Error
: public std::runtime_error
{
public:
Error(const std::string& name, const std::string& message)
: std::runtime_error("[" + name + "] " + message)
, name_(name)
, message_(message)
{
}
const std::string& getName() const
{
return name_;
}
const std::string& getMessage() const
{
return message_;
}
private:
std::string name_;
std::string message_;
};
sdbus::Error createError(int errNo, const std::string& customMsg);
}
#define SDBUS_THROW_ERROR(_MSG, _ERRNO) \
throw sdbus::createError((_ERRNO), (_MSG)) \
/**/
#define SDBUS_THROW_ERROR_IF(_COND, _MSG, _ERRNO) \
if (_COND) SDBUS_THROW_ERROR((_MSG), (_ERRNO)) \
/**/
#endif /* SDBUS_CXX_ERROR_H_ */
+157
View File
@@ -0,0 +1,157 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file IConnection.h
*
* Created on: Nov 8, 2016
* 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_ICONNECTION_H_
#define SDBUS_CXX_ICONNECTION_H_
//#include <cstdint>
#include <string>
#include <memory>
namespace sdbus {
/********************************************//**
* @class IConnection
*
* An interface to D-Bus bus connection. Incorporates implementation
* of both synchronous and asynchronous processing loop.
*
* All methods throw @sdbus::Error in case of failure. The class is
* thread-aware, but not thread-safe.
*
***********************************************/
class IConnection
{
public:
/*!
* @brief Requests D-Bus name on the connection
*
* @param[in] name Name to request
*
* @throws sdbus::Error in case of failure
*/
virtual void requestName(const std::string& name) = 0;
/*!
* @brief Releases D-Bus name on the connection
*
* @param[in] name Name to release
*
* @throws sdbus::Error in case of failure
*/
virtual void releaseName(const std::string& name) = 0;
/*!
* @brief Enters the D-Bus processing loop
*
* The incoming D-Bus messages are processed in the loop. The method
* blocks indefinitely, until unblocked via @leaveProcessingLoop.
*
* @throws sdbus::Error in case of failure
*/
virtual void enterProcessingLoop() = 0;
/*!
* @brief Enters the D-Bus processing loop in a separate thread
*
* The same as @enterProcessingLoop, except that it doesn't block
* because it runs the loop in a separate thread managed internally.
*/
virtual void enterProcessingLoopAsync() = 0;
/*!
* @brief Leaves the D-Bus processing loop
*
* Ends the previously started processing loop.
*
* @throws sdbus::Error in case of failure
*/
virtual void leaveProcessingLoop() = 0;
inline virtual ~IConnection() = 0;
};
IConnection::~IConnection() {}
/*!
* @brief Creates/opens D-Bus system connection
*
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createConnection();
/*!
* @brief Creates/opens D-Bus system connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus system connection
*
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createSystemBusConnection();
/*!
* @brief Creates/opens D-Bus system connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name);
/*!
* @brief Creates/opens D-Bus session connection
*
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createSessionBusConnection();
/*!
* @brief Creates/opens D-Bus session connection with a name
*
* @param[in] name Name to request on the connection after its opening
* @return Connection instance
*
* @throws sdbus::Error in case of failure
*/
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name);
}
#endif /* SDBUS_CXX_ICONNECTION_H_ */
+279
View File
@@ -0,0 +1,279 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file IObject.h
*
* Created on: Nov 8, 2016
* 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_IOBJECT_H_
#define SDBUS_CXX_IOBJECT_H_
#include <sdbus-c++/ConvenienceClasses.h>
#include <sdbus-c++/TypeTraits.h>
#include <functional>
#include <string>
#include <memory>
// Forward declarations
namespace sdbus {
class Message;
class IConnection;
}
namespace sdbus {
/********************************************//**
* @class IObject
*
* An interface to D-Bus object. Provides API for registration
* of methods, signals, properties, and for emitting signals.
*
* All methods throw @c sdbus::Error in case of failure. The class is
* thread-aware, but not thread-safe.
*
***********************************************/
class IObject
{
public:
/*!
* @brief Registers method that the object will provide on D-Bus
*
* @param[in] interfaceName Name of an interface that the method will belong to
* @param[in] methodName Name of the method
* @param[in] inputSignature D-Bus signature of method input parameters
* @param[in] outputSignature D-Bus signature of method output parameters
* @param[in] methodCallback Callback that implements the body of the method
*
* @throws sdbus::Error in case of failure
*/
virtual void registerMethod( const std::string& interfaceName
, const std::string& methodName
, const std::string& inputSignature
, const std::string& outputSignature
, method_callback methodCallback ) = 0;
/*!
* @brief Registers signal that the object will emit on D-Bus
*
* @param[in] interfaceName Name of an interface that the signal will fall under
* @param[in] signalName Name of the signal
* @param[in] signature D-Bus signature of signal parameters
*
* @throws sdbus::Error in case of failure
*/
virtual void registerSignal( const std::string& interfaceName
, const std::string& signalName
, const std::string& signature ) = 0;
/*!
* @brief Registers read-only 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
*
* @throws sdbus::Error in case of failure
*/
virtual void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback ) = 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
*
* @throws sdbus::Error in case of failure
*/
virtual void registerProperty( const std::string& interfaceName
, const std::string& propertyName
, const std::string& signature
, property_get_callback getCallback
, property_set_callback setCallback ) = 0;
/*!
* @brief Finishes the registration and exports object API on D-Bus
*
* The method exports all up to now registered methods, signals and properties on D-Bus.
* Must be called only once, after all methods, signals and properties have been registered.
*
* @throws sdbus::Error in case of failure
*/
virtual void finishRegistration() = 0;
/*!
* @brief Creates a signal message
*
* @param[in] interfaceName Name of an interface that the signal belongs under
* @param[in] signalName Name of the signal
* @return A signal message
*
* Serialize signal arguments into the returned message and emit the signal by passing
* the message with serialized arguments to the @c emitSignal function.
* Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
*
* @throws sdbus::Error in case of failure
*/
virtual Message createSignal(const std::string& interfaceName, const std::string& signalName) = 0;
/*!
* @brief Emits signal on D-Bus
*
* @param[in] message Signal message to be sent out
*
* Note: To avoid messing with messages, use higher-level API defined below.
*
* @throws sdbus::Error in case of failure
*/
virtual void emitSignal(const sdbus::Message& message) = 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
*/
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
*/
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
*/
PropertyRegistrator registerProperty(const std::string& propertyName);
/*!
* @brief Emits signal on D-Bus
*
* @param[in] signalName Name of the signal
* @return A helper object for convenient emission of signals
*
* This is a high-level, convenience way of emitting D-Bus signals that abstracts
* from the D-Bus message concept. Signal arguments are automatically serialized
* in a message and D-Bus signatures automatically deduced from the provided native arguments.
*
* Example of use:
* @code
* int arg1 = ...;
* double arg2 = ...;
* object_.emitSignal("fooSignal").onInterface("com.kistler.foo").withArguments(arg1, arg2);
* @endcode
*
* @throws sdbus::Error in case of failure
*/
SignalEmitter emitSignal(const std::string& signalName);
virtual ~IObject() = 0;
};
inline MethodRegistrator IObject::registerMethod(const std::string& methodName)
{
return MethodRegistrator(*this, methodName);
}
inline SignalRegistrator IObject::registerSignal(const std::string& signalName)
{
return SignalRegistrator(*this, std::move(signalName));
}
inline PropertyRegistrator IObject::registerProperty(const std::string& propertyName)
{
return PropertyRegistrator(*this, std::move(propertyName));
}
inline SignalEmitter IObject::emitSignal(const std::string& signalName)
{
return SignalEmitter(*this, signalName);
}
inline IObject::~IObject() {}
/*!
* @brief Creates instance representing a D-Bus object
*
* @param[in] connection D-Bus connection to be used by the object
* @param[in] objectPath Path of the D-Bus object
* @return Pointer to the object representation instance
*
* The provided connection will be used by the object to export methods,
* issue signals and provide properties.
*
* Code example:
* @code
* auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
* @endcode
*/
std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, std::string objectPath);
}
#include <sdbus-c++/ConvenienceClasses.inl>
#endif /* SDBUS_CXX_IOBJECT_H_ */
+249
View File
@@ -0,0 +1,249 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file IObjectProxy.h
*
* Created on: Nov 8, 2016
* 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_IOBJECTPROXY_H_
#define SDBUS_CXX_IOBJECTPROXY_H_
#include <sdbus-c++/ConvenienceClasses.h>
#include <string>
#include <memory>
#include <functional>
// Forward declarations
namespace sdbus {
class Message;
class IConnection;
}
namespace sdbus {
/********************************************//**
* @class IObjectProxy
*
* An interface to D-Bus object proxy. Provides API for calling
* methods, getting/setting properties, and for registering to signals.
*
* All methods throw @c sdbus::Error in case of failure. The class is
* thread-aware, but not thread-safe.
*
***********************************************/
class IObjectProxy
{
public:
/*!
* @brief Creates a method call message
*
* @param[in] interfaceName Name of an interface that the method is defined under
* @param[in] methodName Name of the method
* @return A method call message message
*
* Serialize method arguments into the returned message and invoke the method by passing
* the message with serialized arguments to the @c callMethod function.
* Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
*
* @throws sdbus::Error in case of failure
*/
virtual Message createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;
/*!
* @brief Calls method on the proxied D-Bus object
*
* @param[in] message Message representing a method call
*
* Note: To avoid messing with messages, use higher-level API defined below.
*
* @throws sdbus::Error in case of failure
*/
virtual Message callMethod(const sdbus::Message& message) = 0;
/*!
* @brief Registers a handler for the desired signal emitted by the proxied D-Bus object
*
* @param[in] interfaceName Name of an interface that the signal belongs to
* @param[in] signalName Name of the signal
* @param[in] signalHandler Callback that implements the body of the signal handler
*
* @throws sdbus::Error in case of failure
*/
virtual void registerSignalHandler( const std::string& interfaceName
, const std::string& signalName
, signal_handler signalHandler ) = 0;
/*!
* @brief Finishes the registration of signal handlers
*
* The method physically subscribes to the desired signals.
* Must be called only once, after all signals have been registered already.
*
* @throws sdbus::Error in case of failure
*/
virtual void finishRegistration() = 0;
/*!
* @brief Calls method on the proxied D-Bus object
*
* @param[in] methodName Name of the method
* @return A helper object for convenient invocation of the method
*
* This is a high-level, convenience way of calling D-Bus methods that abstracts
* from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
* in a message and D-Bus signatures automatically deduced from the provided native arguments
* and return values.
*
* Example of use:
* @code
* int result, a = ..., b = ...;
* object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
* @endcode
*
* @throws sdbus::Error in case of failure
*/
MethodInvoker callMethod(const std::string& methodName);
/*!
* @brief Registers signal handler for a given signal of the proxied D-Bus object
*
* @param[in] signalName Name of the signal
* @return A helper object for convenient registration of the signal handler
*
* This is a high-level, convenience way of registering to D-Bus signals that abstracts
* from the D-Bus message concept. Signal arguments are automatically serialized
* in a message and D-Bus signatures automatically deduced from the parameters
* of the provided native signal callback.
*
* Example of use:
* @code
* object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
* @endcode
*
* @throws sdbus::Error in case of failure
*/
SignalSubscriber uponSignal(const std::string& signalName);
/*!
* @brief Gets value of a property of the proxied D-Bus object
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient getting of property value
*
* This is a high-level, convenience way of reading D-Bus property values that abstracts
* from the D-Bus message concept. sdbus::Variant is returned which shall then be converted
* to the real property type (implicit conversion is supported).
*
* Example of use:
* @code
* int state = object.getProperty("state").onInterface("com.kistler.foo");
* @endcode
*
* @throws sdbus::Error in case of failure
*/
PropertyGetter getProperty(const std::string& propertyName);
/*!
* @brief Sets value of a property of the proxied D-Bus object
*
* @param[in] propertyName Name of the property
* @return A helper object for convenient setting of property value
*
* This is a high-level, convenience way of writing D-Bus property values that abstracts
* from the D-Bus message concept.
*
* Example of use:
* @code
* int state = ...;
* object_.setProperty("state").onInterface("com.kistler.foo").toValue(state);
* @endcode
*
* @throws sdbus::Error in case of failure
*/
PropertySetter setProperty(const std::string& propertyName);
virtual ~IObjectProxy() = 0;
};
inline MethodInvoker IObjectProxy::callMethod(const std::string& methodName)
{
return MethodInvoker(*this, methodName);
}
inline SignalSubscriber IObjectProxy::uponSignal(const std::string& signalName)
{
return SignalSubscriber(*this, signalName);
}
inline PropertyGetter IObjectProxy::getProperty(const std::string& propertyName)
{
return PropertyGetter(*this, propertyName);
}
inline PropertySetter IObjectProxy::setProperty(const std::string& propertyName)
{
return PropertySetter(*this, propertyName);
}
inline IObjectProxy::~IObjectProxy() {}
/*!
* @brief Creates object proxy instance
*
* @param[in] connection D-Bus connection to be used by the proxy object
* @param[in] destination Bus name that provides a D-Bus object
* @param[in] objectPath Path of the D-Bus object
* @return Pointer to the object proxy instance
*
* The provided connection will be used by the proxy to issue calls against the object,
* and signals, if any, will be subscribed to on this connection.
*
* Code example:
* @code
* auto proxy = sdbus::createObjectProxy(connection, "com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( sdbus::IConnection& connection
, std::string destination
, std::string objectPath );
/*!
* @brief Creates object proxy instance that uses its own D-Bus connection
*
* @param[in] destination Bus name that provides a D-Bus object
* @param[in] objectPath Path of the D-Bus object
* @return Pointer to the object proxy instance
*
* This factory overload creates a proxy that manages its own D-Bus connection(s).
*
* Code example:
* @code
* auto proxy = sdbus::createObjectProxy(connection, "com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( std::string destination
, std::string objectPath );
}
#include <sdbus-c++/ConvenienceClasses.inl>
#endif /* SDBUS_CXX_IOBJECTPROXY_H_ */
+120
View File
@@ -0,0 +1,120 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Interfaces.h
*
* Created on: Nov 8, 2016
* 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_INTERFACES_H_
#define SDBUS_CXX_INTERFACES_H_
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IObjectProxy.h>
#include <cassert>
#include <string>
#include <memory>
// Forward declarations
namespace sdbus {
class IConnection;
}
namespace sdbus {
template <typename _Object>
class ObjectHolder
{
protected:
ObjectHolder(std::unique_ptr<_Object>&& object)
: object_(std::move(object))
{
}
const _Object& getObject() const
{
assert(object_ != nullptr);
return *object_;
}
_Object& getObject()
{
assert(object_ != nullptr);
return *object_;
}
private:
std::unique_ptr<_Object> object_;
};
/********************************************//**
* @class Interfaces
*
* A helper template class that a user class representing a D-Bus object
* should inherit from, providing as template arguments the adaptor
* classes representing D-Bus interfaces that the object implements.
*
***********************************************/
template <typename... _Interfaces>
class Interfaces
: private ObjectHolder<IObject>
, public _Interfaces...
{
public:
Interfaces(IConnection& connection, std::string objectPath)
: ObjectHolder<IObject>(createObject(connection, std::move(objectPath)))
, _Interfaces(getObject())...
{
getObject().finishRegistration();
}
};
/********************************************//**
* @class Interfaces
*
* A helper template class that a user class representing a proxy of a
* D-Bus object should inherit from, providing as template arguments the proxy
* classes representing object D-Bus interfaces that the object implements.
*
***********************************************/
template <typename... _Interfaces>
class ProxyInterfaces
: private ObjectHolder<IObjectProxy>
, public _Interfaces...
{
public:
ProxyInterfaces(std::string destination, std::string objectPath)
: ObjectHolder<IObjectProxy>(createObjectProxy(std::move(destination), std::move(objectPath)))
, _Interfaces(getObject())...
{
getObject().finishRegistration();
}
ProxyInterfaces(IConnection& connection, std::string destination, std::string objectPath)
: ObjectHolder<IObjectProxy>(createObjectProxy(connection, std::move(destination), std::move(objectPath)))
, _Interfaces(getObject())...
{
getObject().finishRegistration();
}
};
}
#endif /* SDBUS_CXX_INTERFACES_H_ */
+84
View File
@@ -0,0 +1,84 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Introspection.h
*
* Created on: Dec 13, 2016
* 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_INTROSPECTION_H_
#define SDBUS_CXX_INTROSPECTION_H_
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IObjectProxy.h>
#include <string>
namespace sdbus {
// Proxy for introspection
class introspectable_proxy
{
static constexpr const char* interfaceName = "org.freedesktop.DBus.Introspectable";
protected:
introspectable_proxy(sdbus::IObjectProxy& object)
: object_(object)
{
}
public:
std::string Introspect()
{
std::string xml;
object_.callMethod("Introspect").onInterface(interfaceName).storeResultsTo(xml);
return xml;
}
private:
sdbus::IObjectProxy& object_;
};
// Adaptor is not necessary if we want to rely on sdbus-provided introspection
// class introspectable_adaptor
// {
// static constexpr const char* interfaceName = "org.freedesktop.DBus.Introspectable";
//
// protected:
// introspectable_adaptor(sdbus::IObject& object)
// : object_(object)
// {
// object_.registerMethod("Introspect").onInterface(interfaceName).implementedAs([this](){ return object_.introspect(); });
// }
//
// public:
// std::string introspect()
// {
// std::string xml;
// object_.callMethod("Introspect").onInterface(interfaceName).storeResultsTo(xml);
// return xml;
// }
//
// private:
// sdbus::IObject& object_;
// };
}
#endif /* SDBUS_CXX_INTROSPECTION_H_ */
+330
View File
@@ -0,0 +1,330 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Message.h
*
* Created on: Nov 9, 2016
* 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_MESSAGE_H_
#define SDBUS_CXX_MESSAGE_H_
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Error.h>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <utility>
#include <cstdint>
#include <cassert>
#include <iostream>
// Forward declarations
namespace sdbus {
class Variant;
class ObjectPath;
class Signature;
template <typename... _ValueTypes> class Struct;
}
namespace sdbus {
/********************************************//**
* @class Message
*
* Message represents a D-Bus message, which can be either method call message,
* method reply message, signal message, or a plain message serving as a storage
* for serialized data.
*
* Serialization and deserialization functions are provided for types supported
* by D-Bus.
*
* You don't need to work with this class directly if you use high-level APIs
* of @c IObject and @c IObjectProxy.
*
***********************************************/
class Message
{
public:
enum class Type
{
ePlainMessage
, eMethodCall
, eMethodReply
, eSignal
};
Message() = default;
Message(void *msg, Type type = Type::ePlainMessage) noexcept;
Message(const Message&) noexcept;
Message& operator=(const Message&) noexcept;
Message(Message&& other) noexcept;
Message& operator=(Message&& other) noexcept;
~Message();
Message& operator<<(bool item);
Message& operator<<(int16_t item);
Message& operator<<(int32_t item);
Message& operator<<(int64_t item);
Message& operator<<(uint8_t item);
Message& operator<<(uint16_t item);
Message& operator<<(uint32_t item);
Message& operator<<(uint64_t item);
Message& operator<<(double item);
Message& operator<<(const char *item);
Message& operator<<(const std::string &item);
Message& operator<<(const Variant &item);
Message& operator<<(const ObjectPath &item);
Message& operator<<(const Signature &item);
Message& operator>>(bool& item);
Message& operator>>(int16_t& item);
Message& operator>>(int32_t& item);
Message& operator>>(int64_t& item);
Message& operator>>(uint8_t& item);
Message& operator>>(uint16_t& item);
Message& operator>>(uint32_t& item);
Message& operator>>(uint64_t& item);
Message& operator>>(double& item);
Message& operator>>(char*& item);
Message& operator>>(std::string &item);
Message& operator>>(Variant &item);
Message& operator>>(ObjectPath &item);
Message& operator>>(Signature &item);
Message& openContainer(const std::string& signature);
Message& closeContainer();
Message& openDictEntry(const std::string& signature);
Message& closeDictEntry();
Message& openVariant(const std::string& signature);
Message& closeVariant();
Message& openStruct(const std::string& signature);
Message& closeStruct();
Message& enterContainer(const std::string& signature);
Message& exitContainer();
Message& enterDictEntry(const std::string& signature);
Message& exitDictEntry();
Message& enterVariant(const std::string& signature);
Message& exitVariant();
Message& enterStruct(const std::string& signature);
Message& exitStruct();
operator bool() const;
void clearFlags();
std::string getInterfaceName() const;
std::string getMemberName() const;
void peekType(std::string& type, std::string& contents) const;
bool isValid() const;
bool isEmpty() const;
Type getType() const;
void copyTo(Message& destination, bool complete) const;
void seal();
void rewind(bool complete);
Message createReply() const;
Message send() const;
private:
void* msg_{};
Type type_{Type::ePlainMessage};
mutable bool ok_{true};
};
template <typename _Element>
inline Message& operator<<(Message& msg, const std::vector<_Element>& items)
{
msg.openContainer(signature_of<_Element>::str());
for (const auto& item : items)
msg << item;
msg.closeContainer();
return msg;
}
template <typename _Key, typename _Value>
inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items)
{
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
msg.openContainer(arraySignature);
for (const auto& item : items)
{
msg.openDictEntry(dictEntrySignature);
msg << item.first;
msg << item.second;
msg.closeDictEntry();
}
msg.closeContainer();
return msg;
}
namespace detail
{
template <typename... _Args>
void serialize_pack(Message& msg, _Args&&... args)
{
// Use initializer_list because it guarantees left to right order, and can be empty
using _ = std::initializer_list<int>;
// We are not interested in the list itself, but in the side effects
(void)_{(void(msg << std::forward<_Args>(args)), 0)...};
}
template <class _Tuple, std::size_t... _Is>
void serialize_tuple( Message& msg
, const _Tuple& t
, std::index_sequence<_Is...>)
{
serialize_pack(msg, std::get<_Is>(t)...);
}
}
template <typename... _ValueTypes>
inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
assert(structSignature.size() > 2);
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
msg.openStruct(structContentSignature);
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
msg.closeStruct();
return msg;
}
template <typename... _ValueTypes>
inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item)
{
detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
return msg;
}
template <typename _Element>
inline Message& operator>>(Message& msg, std::vector<_Element>& items)
{
if(!msg.enterContainer(signature_of<_Element>::str()))
return msg;
while (true)
{
_Element elem;
if (msg >> elem)
items.emplace_back(std::move(elem));
else
break;
}
msg.clearFlags();
msg.exitContainer();
return msg;
}
template <typename _Key, typename _Value>
inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items)
{
const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str();
const std::string arraySignature = "{" + dictEntrySignature + "}";
if (!msg.enterContainer(arraySignature))
return msg;
while (true)
{
if (!msg.enterDictEntry(dictEntrySignature))
break;
_Key key;
_Value value;
msg >> key >> value;
items.emplace(std::move(key), std::move(value));
msg.exitDictEntry();
}
msg.clearFlags();
msg.exitContainer();
return msg;
}
namespace detail
{
template <typename... _Args>
void deserialize_pack(Message& msg, _Args&... args)
{
// Use initializer_list because it guarantees left to right order, and can be empty
using _ = std::initializer_list<int>;
// We are not interested in the list itself, but in the side effects
(void)_{(void(msg >> args), 0)...};
}
template <class _Tuple, std::size_t... _Is>
void deserialize_tuple( Message& msg
, _Tuple& t
, std::index_sequence<_Is...> )
{
deserialize_pack(msg, std::get<_Is>(t)...);
}
}
template <typename... _ValueTypes>
inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item)
{
auto structSignature = signature_of<Struct<_ValueTypes...>>::str();
// Remove opening and closing parenthesis from the struct signature to get contents signature
auto structContentSignature = structSignature.substr(1, structSignature.size()-2);
if (!msg.enterStruct(structContentSignature))
return msg;
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
msg.exitStruct();
return msg;
}
template <typename... _ValueTypes>
inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item)
{
detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{});
return msg;
}
}
#endif /* SDBUS_CXX_MESSAGE_H_ */
+441
View File
@@ -0,0 +1,441 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file TypeTraits.h
*
* Created on: Nov 9, 2016
* 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_TYPETRAITS_H_
#define SDBUS_CXX_TYPETRAITS_H_
#include <string>
#include <vector>
#include <map>
#include <cstdint>
#include <functional>
#include <tuple>
// Forward declarations
namespace sdbus {
class Variant;
template <typename... _ValueTypes> class Struct;
class ObjectPath;
class Signature;
class Message;
}
namespace sdbus {
using method_callback = std::function<void(Message& msg, Message& reply)>;
using signal_handler = std::function<void(Message& signal)>;
using property_set_callback = std::function<void(Message& msg)>;
using property_get_callback = std::function<void(Message& reply)>;
// Primary template
template <typename _T>
struct signature_of
{
static const std::string str()
{
// sizeof(_T) < 0 is here to make compiler not being able to figure out
// the assertion expression before the template instantiation takes place.
static_assert(sizeof(_T) < 0, "Unknown DBus type");
return "";
}
};
template <>
struct signature_of<void>
{
static const std::string str()
{
return "";
}
};
template <>
struct signature_of<bool>
{
static const std::string str()
{
return "b";
}
};
template <>
struct signature_of<uint8_t>
{
static const std::string str()
{
return "y";
}
};
template <>
struct signature_of<int16_t>
{
static const std::string str()
{
return "n";
}
};
template <>
struct signature_of<uint16_t>
{
static const std::string str()
{
return "q";
}
};
template <>
struct signature_of<int32_t>
{
static const std::string str()
{
return "i";
}
};
template <>
struct signature_of<uint32_t>
{
static const std::string str()
{
return "u";
}
};
template <>
struct signature_of<int64_t>
{
static const std::string str()
{
return "x";
}
};
template <>
struct signature_of<uint64_t>
{
static const std::string str()
{
return "t";
}
};
template <>
struct signature_of<double>
{
static const std::string str()
{
return "d";
}
};
template <>
struct signature_of<char*>
{
static const std::string str()
{
return "s";
}
};
template <>
struct signature_of<const char*>
{
static const std::string str()
{
return "s";
}
};
template <std::size_t _N>
struct signature_of<char[_N]>
{
static const std::string str()
{
return "s";
}
};
template <std::size_t _N>
struct signature_of<const char[_N]>
{
static const std::string str()
{
return "s";
}
};
template <>
struct signature_of<std::string>
{
static const std::string str()
{
return "s";
}
};
template <typename... _ValueTypes>
struct signature_of<Struct<_ValueTypes...>>
{
static const std::string str()
{
std::initializer_list<std::string> signatures{signature_of<_ValueTypes>::str()...};
std::string signature;
signature += "(";
for (const auto& item : signatures)
signature += item;
signature += ")";
return signature;
}
};
template <>
struct signature_of<Variant>
{
static const std::string str()
{
return "v";
}
};
template <>
struct signature_of<ObjectPath>
{
static const std::string str()
{
return "o";
}
};
template <>
struct signature_of<Signature>
{
static const std::string str()
{
return "g";
}
};
template <typename _Element>
struct signature_of<std::vector<_Element>>
{
static const std::string str()
{
return "a" + signature_of<_Element>::str();
}
};
template <typename _Key, typename _Value>
struct signature_of<std::map<_Key, _Value>>
{
static const std::string str()
{
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
}
};
template <typename _Type>
struct function_traits
: public function_traits<decltype(&_Type::operator())>
{};
template <typename _Type>
struct function_traits<const _Type>
: public function_traits<_Type>
{};
template <typename _Type>
struct function_traits<_Type&>
: public function_traits<_Type>
{};
// Function traits implementation inspired by (c) kennytm,
// https://github.com/kennytm/utils/blob/master/traits.hpp
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_Args...)>
{
typedef _ReturnType result_type;
typedef std::tuple<_Args...> arguments_type;
typedef _ReturnType function_type(_Args...);
static constexpr std::size_t arity = sizeof...(_Args);
template <size_t _Idx>
struct arg
{
typedef std::tuple_element_t<_Idx, std::tuple<_Args...>> type;
};
template <size_t _Idx>
using arg_t = typename arg<_Idx>::type;
};
template <typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(*)(_Args...)>
: public function_traits<_ReturnType(_Args...)>
{};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...)>
: public function_traits<_ReturnType(_Args...)>
{
typedef _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const>
: public function_traits<_ReturnType(_Args...)>
{
typedef const _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile>
: public function_traits<_ReturnType(_Args...)>
{
typedef volatile _ClassType& owner_type;
};
template <typename _ClassType, typename _ReturnType, typename... _Args>
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile>
: public function_traits<_ReturnType(_Args...)>
{
typedef const volatile _ClassType& owner_type;
};
template <typename FunctionType>
struct function_traits<std::function<FunctionType>>
: public function_traits<FunctionType>
{};
template <typename _FunctionType, size_t _Idx>
using function_argument_t = typename function_traits<_FunctionType>::template arg_t<_Idx>;
template <typename _FunctionType>
using function_result_t = typename function_traits<_FunctionType>::result_type;
template <typename _Type>
struct aggregate_signature
{
static const std::string str()
{
return signature_of<std::decay_t<_Type>>::str();
}
};
template <typename... _Types>
struct aggregate_signature<std::tuple<_Types...>>
{
static const std::string str()
{
std::initializer_list<std::string> signatures{signature_of<std::decay_t<_Types>>::str()...};
std::string signature;
for (const auto& item : signatures)
signature += item;
return signature;
}
};
// Get a tuple of function input argument types from function signature.
// But first, convert provided function signature to the standardized form `out(in...)'.
template <typename _Function>
struct tuple_of_function_input_arg_types
: public tuple_of_function_input_arg_types<typename function_traits<_Function>::function_type>
{};
// Get a tuple of function input argument types from function signature.
// Function signature is expected in the standardized form `out(in...)'.
template <typename _ReturnType, typename... _Args>
struct tuple_of_function_input_arg_types<_ReturnType(_Args...)>
{
// Arguments may be cv-qualified and may be references, so we have to strip cv and references
// with decay_t in order to get real 'naked' types.
// Example: for a function with signature void(const int i, const std::vector<float> v, double d)
// the `type' will be `std::tuple<int, std::vector<float>, double>'.
typedef std::tuple<std::decay_t<_Args>...> type;
};
template <typename _Function>
using tuple_of_function_input_arg_types_t = typename tuple_of_function_input_arg_types<_Function>::type;
template <typename _Function>
struct signature_of_function_input_arguments
{
static const std::string str()
{
return aggregate_signature<tuple_of_function_input_arg_types_t<_Function>>::str();
}
};
template <typename _Function>
struct signature_of_function_output_arguments
{
static const std::string str()
{
return aggregate_signature<function_result_t<_Function>>::str();
}
};
namespace detail
{
// Version of apply_impl for functions returning non-void values.
// In this case just forward function return value.
template <class _Function, class _Tuple, std::size_t... _I>
constexpr decltype(auto) apply_impl( _Function&& f
, _Tuple&& t
, std::index_sequence<_I...>
, std::enable_if_t<!std::is_void<function_result_t<_Function>>::value>* = nullptr)
{
return std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...);
}
// Version of apply_impl for functions returning void.
// In this case, to have uniform code on the caller side, return empty tuple, our synonym for `void'.
template <class _Function, class _Tuple, std::size_t... _I>
constexpr decltype(auto) apply_impl( _Function&& f
, _Tuple&& t
, std::index_sequence<_I...>
, std::enable_if_t<std::is_void<function_result_t<_Function>>::value>* = nullptr)
{
std::forward<_Function>(f)(std::get<_I>(std::forward<_Tuple>(t))...);
return std::tuple<>{};
}
}
// Convert tuple `t' of values into a list of arguments
// and invoke function `f' with those arguments.
template <class _Function, class _Tuple>
constexpr decltype(auto) apply(_Function&& f, _Tuple&& t)
{
return detail::apply_impl( std::forward<_Function>(f)
, std::forward<_Tuple>(t)
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
}
}
#endif /* SDBUS_CXX_TYPETRAITS_H_ */
+137
View File
@@ -0,0 +1,137 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Types.h
*
* Created on: Nov 23, 2016
* 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_TYPES_H_
#define SDBUS_CXX_TYPES_H_
#include <sdbus-c++/Message.h>
#include <sdbus-c++/TypeTraits.h>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <memory>
#include <tuple>
namespace sdbus {
/********************************************//**
* @class Variant
*
* Variant can hold value of any D-Bus-supported type.
*
***********************************************/
class Variant
{
public:
Variant();
template <typename _ValueType>
Variant(const _ValueType& value)
: Variant()
{
msg_.openVariant(signature_of<_ValueType>::str());
msg_ << value;
msg_.closeVariant();
msg_.seal();
}
template <typename _ValueType>
_ValueType get() const
{
_ValueType val;
msg_.rewind(false);
msg_.enterVariant(signature_of<_ValueType>::str());
msg_ >> val;
msg_.exitVariant();
return val;
}
template <typename _ValueType>
operator _ValueType() const
{
return get<_ValueType>();
}
template <typename _Type>
bool containsValueOfType() const
{
return signature_of<_Type>::str() == peekValueType();
}
bool isEmpty() const;
void serializeTo(Message& msg) const;
void deserializeFrom(Message& msg);
std::string peekValueType() const;
private:
mutable Message msg_{};
};
template <typename... _ValueTypes>
class Struct
: public std::tuple<_ValueTypes...>
{
public:
using std::tuple<_ValueTypes...>::tuple;
template <std::size_t _I>
auto& get()
{
return std::get<_I>(*this);
}
template <std::size_t _I>
const auto& get() const
{
return std::get<_I>(*this);
}
};
template<typename... _Elements>
constexpr Struct<std::decay_t<_Elements>...>
make_struct(_Elements&&... args)
{
typedef Struct<std::decay_t<_Elements>...> result_type;
return result_type(std::forward<_Elements>(args)...);
}
class ObjectPath : public std::string
{
public:
using std::string::string;
using std::string::operator=;
};
class Signature : public std::string
{
public:
using std::string::string;
using std::string::operator=;
};
}
#endif /* SDBUS_CXX_TYPES_H_ */
+34
View File
@@ -0,0 +1,34 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file sdbus-c++.h
*
* Created on: Jan 19, 2017
* 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/>.
*/
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IObjectProxy.h>
#include <sdbus-c++/Interfaces.h>
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Types.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/Introspection.h>
#include <sdbus-c++/Error.h>