forked from Kistler-Group/sdbus-cpp
refactor: enable compile-time D-Bus signature generation (#425)
Since sdbus-c++ knows types of D-Bus call/signal/property input/output parameters at compile time, why not assemble the D-Bus signature strings at compile time, too, instead of assembling them at run time as std::string with likely cost of (unnecessary) heap allocations... std::array is well supported constexpr type in C++20, so we harness it to build the D-Bus signature string and store it into the binary at compile time.
This commit is contained in:
+106
-42
@@ -161,22 +161,38 @@ namespace sdbus {
|
||||
template <typename... _ValueTypes>
|
||||
Message& operator>>(std::tuple<_ValueTypes...>& item);
|
||||
|
||||
Message& openContainer(const std::string& signature);
|
||||
template <typename _ElementType>
|
||||
Message& openContainer();
|
||||
Message& openContainer(const char* signature);
|
||||
Message& closeContainer();
|
||||
Message& openDictEntry(const std::string& signature);
|
||||
template <typename _KeyType, typename _ValueType>
|
||||
Message& openDictEntry();
|
||||
Message& openDictEntry(const char* signature);
|
||||
Message& closeDictEntry();
|
||||
Message& openVariant(const std::string& signature);
|
||||
template <typename _ValueType>
|
||||
Message& openVariant();
|
||||
Message& openVariant(const char* signature);
|
||||
Message& closeVariant();
|
||||
Message& openStruct(const std::string& signature);
|
||||
template <typename... _ValueTypes>
|
||||
Message& openStruct();
|
||||
Message& openStruct(const char* signature);
|
||||
Message& closeStruct();
|
||||
|
||||
Message& enterContainer(const std::string& signature);
|
||||
template <typename _ElementType>
|
||||
Message& enterContainer();
|
||||
Message& enterContainer(const char* signature);
|
||||
Message& exitContainer();
|
||||
Message& enterDictEntry(const std::string& signature);
|
||||
template <typename _KeyType, typename _ValueType>
|
||||
Message& enterDictEntry();
|
||||
Message& enterDictEntry(const char* signature);
|
||||
Message& exitDictEntry();
|
||||
Message& enterVariant(const std::string& signature);
|
||||
template <typename _ValueType>
|
||||
Message& enterVariant();
|
||||
Message& enterVariant(const char* signature);
|
||||
Message& exitVariant();
|
||||
Message& enterStruct(const std::string& signature);
|
||||
template <typename... _ValueTypes>
|
||||
Message& enterStruct();
|
||||
Message& enterStruct(const char* signature);
|
||||
Message& exitStruct();
|
||||
|
||||
Message& appendArray(char type, const void *ptr, size_t size);
|
||||
@@ -320,8 +336,9 @@ namespace sdbus {
|
||||
template <typename ...Elements>
|
||||
inline Message& Message::operator<<(const std::variant<Elements...>& value)
|
||||
{
|
||||
std::visit([this](const auto& inner){
|
||||
openVariant(signature_of<decltype(inner)>::str());
|
||||
std::visit([this](const auto& inner)
|
||||
{
|
||||
openVariant<decltype(inner)>();
|
||||
*this << inner;
|
||||
closeVariant();
|
||||
}, value);
|
||||
@@ -370,11 +387,12 @@ namespace sdbus {
|
||||
// otherwise use step-by-step serialization of individual elements.
|
||||
if constexpr (signature_of<ElementType>::is_trivial_dbus_type && !std::is_same_v<ElementType, bool>)
|
||||
{
|
||||
appendArray(*signature_of<ElementType>::str().c_str(), items.data(), items.size() * sizeof(ElementType));
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<ElementType>);
|
||||
appendArray(*signature.data(), items.data(), items.size() * sizeof(ElementType));
|
||||
}
|
||||
else
|
||||
{
|
||||
openContainer(signature_of<ElementType>::str());
|
||||
openContainer<ElementType>();
|
||||
|
||||
for (const auto& item : items)
|
||||
*this << item;
|
||||
@@ -403,16 +421,13 @@ namespace sdbus {
|
||||
inline void Message::serializeDictionary(const _Dictionary& items)
|
||||
{
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using ValueType = typename _Dictionary::mapped_type;
|
||||
using MappedType = typename _Dictionary::mapped_type;
|
||||
|
||||
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
openContainer(arraySignature);
|
||||
openContainer<DictEntry<KeyType, MappedType>>();
|
||||
|
||||
for (const auto& item : items)
|
||||
{
|
||||
openDictEntry(dictEntrySignature);
|
||||
openDictEntry<KeyType, MappedType>();
|
||||
*this << item.first;
|
||||
*this << item.second;
|
||||
closeDictEntry();
|
||||
@@ -441,12 +456,7 @@ namespace sdbus {
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& Message::operator<<(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);
|
||||
|
||||
openStruct(structContentSignature);
|
||||
openStruct<_ValueTypes...>();
|
||||
detail::serialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
closeStruct();
|
||||
|
||||
@@ -465,11 +475,13 @@ namespace sdbus {
|
||||
template <typename _Element, typename... _Elements>
|
||||
bool deserialize_variant(Message& msg, std::variant<_Elements...>& value, const std::string& signature)
|
||||
{
|
||||
if (signature != signature_of<_Element>::str())
|
||||
constexpr auto elemSignature = sdbus::signature_of_v<_Element>;
|
||||
// TODO: Try to optimize
|
||||
if (signature != std::string(elemSignature.begin(), elemSignature.end()))
|
||||
return false;
|
||||
|
||||
_Element temp;
|
||||
msg.enterVariant(signature);
|
||||
msg.enterVariant(signature.c_str());
|
||||
msg >> temp;
|
||||
msg.exitVariant();
|
||||
value = std::move(temp);
|
||||
@@ -482,6 +494,7 @@ namespace sdbus {
|
||||
{
|
||||
std::string type;
|
||||
std::string contentType;
|
||||
// TODO: Refactor ppekType prior to release/v2.0 to return pair of const char* or string_view...
|
||||
peekType(type, contentType);
|
||||
bool result = (detail::deserialize_variant<Elements>(*this, value, contentType) || ...);
|
||||
SDBUS_THROW_ERROR_IF(!result, "Failed to deserialize variant: signature did not match any of the variant types", EINVAL);
|
||||
@@ -548,7 +561,8 @@ namespace sdbus {
|
||||
size_t arraySize{};
|
||||
const ElementType* arrayPtr{};
|
||||
|
||||
readArray(*signature_of<ElementType>::str().c_str(), (const void**)&arrayPtr, &arraySize);
|
||||
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<ElementType>);
|
||||
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
|
||||
|
||||
size_t elementsInMsg = arraySize / sizeof(ElementType);
|
||||
bool notEnoughSpace = items.size() < elementsInMsg;
|
||||
@@ -563,7 +577,8 @@ namespace sdbus {
|
||||
size_t arraySize{};
|
||||
const _Element* arrayPtr{};
|
||||
|
||||
readArray(*signature_of<_Element>::str().c_str(), (const void**)&arrayPtr, &arraySize);
|
||||
constexpr auto signature = as_null_terminated(sdbus::signature_of_v<_Element>);
|
||||
readArray(*signature.data(), (const void**)&arrayPtr, &arraySize);
|
||||
|
||||
items.insert(items.end(), arrayPtr, arrayPtr + (arraySize / sizeof(_Element)));
|
||||
}
|
||||
@@ -573,7 +588,7 @@ namespace sdbus {
|
||||
{
|
||||
using ElementType = typename _Array::value_type;
|
||||
|
||||
if(!enterContainer(signature_of<ElementType>::str()))
|
||||
if(!enterContainer<ElementType>())
|
||||
return;
|
||||
|
||||
for (auto& elem : items)
|
||||
@@ -590,7 +605,7 @@ namespace sdbus {
|
||||
template <typename _Element, typename _Allocator>
|
||||
void Message::deserializeArraySlow(std::vector<_Element, _Allocator>& items)
|
||||
{
|
||||
if(!enterContainer(signature_of<_Element>::str()))
|
||||
if(!enterContainer<_Element>())
|
||||
return;
|
||||
|
||||
while (true)
|
||||
@@ -627,21 +642,18 @@ namespace sdbus {
|
||||
inline void Message::deserializeDictionary(_Dictionary& items)
|
||||
{
|
||||
using KeyType = typename _Dictionary::key_type;
|
||||
using ValueType = typename _Dictionary::mapped_type;
|
||||
using MappedType = typename _Dictionary::mapped_type;
|
||||
|
||||
const std::string dictEntrySignature = signature_of<KeyType>::str() + signature_of<ValueType>::str();
|
||||
const std::string arraySignature = "{" + dictEntrySignature + "}";
|
||||
|
||||
if (!enterContainer(arraySignature))
|
||||
if (!enterContainer<DictEntry<KeyType, MappedType>>())
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!enterDictEntry(dictEntrySignature))
|
||||
if (!enterDictEntry<KeyType, MappedType>())
|
||||
break;
|
||||
|
||||
KeyType key;
|
||||
ValueType value;
|
||||
MappedType value;
|
||||
*this >> key >> value;
|
||||
|
||||
items.emplace(std::move(key), std::move(value));
|
||||
@@ -674,11 +686,7 @@ namespace sdbus {
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& Message::operator>>(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 (!enterStruct(structContentSignature))
|
||||
if (!enterStruct<_ValueTypes...>())
|
||||
return *this;
|
||||
|
||||
detail::deserialize_tuple(*this, item, std::index_sequence_for<_ValueTypes...>{});
|
||||
@@ -695,6 +703,62 @@ namespace sdbus {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename _ElementType>
|
||||
inline Message& Message::openContainer()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
|
||||
return openContainer(signature.data());
|
||||
}
|
||||
|
||||
template <typename _KeyType, typename _ValueType>
|
||||
inline Message& Message::openDictEntry()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
|
||||
return openDictEntry(signature.data());
|
||||
}
|
||||
|
||||
template <typename _ValueType>
|
||||
inline Message& Message::openVariant()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
|
||||
return openVariant(signature.data());
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& Message::openStruct()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
|
||||
return openStruct(signature.data());
|
||||
}
|
||||
|
||||
template <typename _ElementType>
|
||||
inline Message& Message::enterContainer()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<_ElementType>);
|
||||
return enterContainer(signature.data());
|
||||
}
|
||||
|
||||
template <typename _KeyType, typename _ValueType>
|
||||
inline Message& Message::enterDictEntry()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_KeyType, _ValueType>>);
|
||||
return enterDictEntry(signature.data());
|
||||
}
|
||||
|
||||
template <typename _ValueType>
|
||||
inline Message& Message::enterVariant()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<_ValueType>);
|
||||
return enterVariant(signature.data());
|
||||
}
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
inline Message& Message::enterStruct()
|
||||
{
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<std::tuple<_ValueTypes...>>);
|
||||
return enterStruct(signature.data());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_MESSAGE_H_ */
|
||||
|
||||
+132
-234
@@ -44,6 +44,7 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
@@ -54,6 +55,7 @@ namespace sdbus {
|
||||
class ObjectPath;
|
||||
class Signature;
|
||||
class UnixFd;
|
||||
template<typename _T1, typename _T2> using DictEntry = std::pair<_T1, _T2>;
|
||||
class BusName;
|
||||
class InterfaceName;
|
||||
class MemberName;
|
||||
@@ -65,6 +67,7 @@ namespace sdbus {
|
||||
class PropertyGetReply;
|
||||
template <typename... _Results> class Result;
|
||||
class Error;
|
||||
template <typename _T, typename _Enable = void> struct signature_of;
|
||||
}
|
||||
|
||||
namespace sdbus {
|
||||
@@ -106,253 +109,171 @@ namespace sdbus {
|
||||
// Helper for static assert
|
||||
template <class... _T> constexpr bool always_false = false;
|
||||
|
||||
// Helper operator+ for concatenation of `std::array`s
|
||||
template <typename _T, std::size_t _N1, std::size_t _N2>
|
||||
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs);
|
||||
|
||||
// Template specializations for getting D-Bus signatures from C++ types
|
||||
template <typename _T, typename _Enable = void>
|
||||
template <typename _T>
|
||||
constexpr auto signature_of_v = signature_of<_T>::value;
|
||||
|
||||
template <typename _T, typename _Enable>
|
||||
struct signature_of
|
||||
{
|
||||
static constexpr bool is_valid = false;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
static constexpr void* value = []
|
||||
{
|
||||
// See using-sdbus-c++.md, section "Extending sdbus-c++ type system",
|
||||
// on how to teach sdbus-c++ about your custom types
|
||||
static_assert(always_false<_T>, "Unsupported DBus type (template specializations are needed for your custom types)");
|
||||
return "";
|
||||
}
|
||||
static_assert(always_false<_T>, "Unsupported D-Bus type (specialize `signature_of` for your custom types)");
|
||||
};
|
||||
};
|
||||
|
||||
template <typename _T>
|
||||
struct signature_of<const _T>
|
||||
: public signature_of<_T>
|
||||
struct signature_of<const _T> : signature_of<_T>
|
||||
{};
|
||||
|
||||
template <typename _T>
|
||||
struct signature_of<_T&>
|
||||
: public signature_of<_T>
|
||||
struct signature_of<volatile _T> : signature_of<_T>
|
||||
{};
|
||||
|
||||
template <typename _T>
|
||||
struct signature_of<_T&> : signature_of<_T>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<void>
|
||||
{
|
||||
static constexpr std::array<char, 0> value{};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<bool>
|
||||
{
|
||||
static constexpr std::array value{'b'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "b";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint8_t>
|
||||
{
|
||||
static constexpr std::array value{'y'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "y";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int16_t>
|
||||
{
|
||||
static constexpr std::array value{'n'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "n";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint16_t>
|
||||
{
|
||||
static constexpr std::array value{'q'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "q";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int32_t>
|
||||
{
|
||||
static constexpr std::array value{'i'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "i";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint32_t>
|
||||
{
|
||||
static constexpr std::array value{'u'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "u";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<int64_t>
|
||||
{
|
||||
static constexpr std::array value{'x'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "x";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<uint64_t>
|
||||
{
|
||||
static constexpr std::array value{'t'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "t";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<double>
|
||||
{
|
||||
static constexpr std::array value{'d'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = true;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "d";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<char*>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<const char*>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<char[_N]>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<const char[_N]>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<std::string>
|
||||
{
|
||||
static constexpr std::array value{'s'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<char*> : signature_of<std::string>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<const char*> : signature_of<std::string>
|
||||
{};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<char[_N]> : signature_of<std::string>
|
||||
{};
|
||||
|
||||
template <std::size_t _N>
|
||||
struct signature_of<const char[_N]> : signature_of<std::string>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<BusName> : signature_of<std::string>
|
||||
{
|
||||
};
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<InterfaceName> : signature_of<std::string>
|
||||
{
|
||||
};
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct signature_of<MemberName> : signature_of<std::string>
|
||||
{
|
||||
};
|
||||
{};
|
||||
|
||||
template <typename... _ValueTypes>
|
||||
struct signature_of<Struct<_ValueTypes...>>
|
||||
{
|
||||
static constexpr std::array contents = (signature_of_v<_ValueTypes> + ...);
|
||||
static constexpr std::array value = std::array{'('} + contents + std::array{')'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
std::string signature;
|
||||
signature += "(";
|
||||
(signature += ... += signature_of<_ValueTypes>::str());
|
||||
signature += ")";
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<Variant>
|
||||
{
|
||||
static constexpr std::array value{'v'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "v";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Elements>
|
||||
@@ -362,74 +283,52 @@ namespace sdbus {
|
||||
template <>
|
||||
struct signature_of<ObjectPath>
|
||||
{
|
||||
static constexpr std::array value{'o'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "o";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<Signature>
|
||||
{
|
||||
static constexpr std::array value{'g'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "g";
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct signature_of<UnixFd>
|
||||
{
|
||||
static constexpr std::array value{'h'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "h";
|
||||
}
|
||||
template <typename _T1, typename _T2>
|
||||
struct signature_of<DictEntry<_T1, _T2>>
|
||||
{
|
||||
static constexpr std::array value = std::array{'{'} + signature_of_v<std::tuple<_T1, _T2>> + std::array{'}'};
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
|
||||
template <typename _Element, typename _Allocator>
|
||||
struct signature_of<std::vector<_Element, _Allocator>>
|
||||
{
|
||||
static constexpr std::array value = std::array{'a'} + signature_of_v<_Element>;
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a" + signature_of<_Element>::str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Element, std::size_t _Size>
|
||||
struct signature_of<std::array<_Element, _Size>>
|
||||
struct signature_of<std::array<_Element, _Size>> : signature_of<std::vector<_Element>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a" + signature_of<_Element>::str();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename _Element, std::size_t _Extent>
|
||||
struct signature_of<std::span<_Element, _Extent>>
|
||||
struct signature_of<std::span<_Element, _Extent>> : signature_of<std::vector<_Element>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a" + signature_of<_Element>::str();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -438,46 +337,49 @@ namespace sdbus {
|
||||
: public signature_of<std::underlying_type_t<_Enum>>
|
||||
{};
|
||||
|
||||
|
||||
template <typename _Key, typename _Value, typename _Compare, typename _Allocator>
|
||||
struct signature_of<std::map<_Key, _Value, _Compare, _Allocator>>
|
||||
{
|
||||
static constexpr std::array contents = signature_of_v<std::tuple<_Key, _Value>>;
|
||||
static constexpr std::array dict_entry = std::array{'{'} + contents + std::array{'}'};
|
||||
static constexpr std::array value = std::array{'a'} + dict_entry;
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Key, typename _Value, typename _Hash, typename _KeyEqual, typename _Allocator>
|
||||
struct signature_of<std::unordered_map<_Key, _Value, _Hash, _KeyEqual, _Allocator>>
|
||||
: signature_of<std::map<_Key, _Value>>
|
||||
{
|
||||
static constexpr bool is_valid = true;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
|
||||
static const std::string str()
|
||||
{
|
||||
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... _Types>
|
||||
struct signature_of<std::tuple<_Types...>> // A simple concatenation of signatures of _Types
|
||||
{
|
||||
static constexpr std::array value = (std::array<char, 0>{} + ... + signature_of_v<_Types>);
|
||||
static constexpr bool is_valid = false;
|
||||
static constexpr bool is_trivial_dbus_type = false;
|
||||
};
|
||||
|
||||
// To simplify conversions of arrays to C strings
|
||||
template <typename _T, std::size_t _N>
|
||||
constexpr auto as_null_terminated(std::array<_T, _N> arr)
|
||||
{
|
||||
return arr + std::array<_T, 1>{0};
|
||||
}
|
||||
|
||||
// Function traits implementation inspired by (c) kennytm,
|
||||
// https://github.com/kennytm/utils/blob/master/traits.hpp
|
||||
template <typename _Type>
|
||||
struct function_traits
|
||||
: public function_traits<decltype(&_Type::operator())>
|
||||
struct function_traits : function_traits<decltype(&_Type::operator())>
|
||||
{};
|
||||
|
||||
template <typename _Type>
|
||||
struct function_traits<const _Type>
|
||||
: public function_traits<_Type>
|
||||
struct function_traits<const _Type> : function_traits<_Type>
|
||||
{};
|
||||
|
||||
template <typename _Type>
|
||||
struct function_traits<_Type&>
|
||||
: public function_traits<_Type>
|
||||
struct function_traits<_Type&> : function_traits<_Type>
|
||||
{};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
@@ -517,72 +419,62 @@ namespace sdbus {
|
||||
};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_Args...)>
|
||||
: public function_traits_base<_ReturnType, _Args...>
|
||||
struct function_traits<_ReturnType(_Args...)> : function_traits_base<_ReturnType, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = false;
|
||||
static constexpr bool has_error_param = false;
|
||||
};
|
||||
|
||||
template <typename... _Args>
|
||||
struct function_traits<void(std::optional<Error>, _Args...)>
|
||||
: public function_traits_base<void, _Args...>
|
||||
struct function_traits<void(std::optional<Error>, _Args...)> : function_traits_base<void, _Args...>
|
||||
{
|
||||
static constexpr bool has_error_param = true;
|
||||
};
|
||||
|
||||
template <typename... _Args, typename... _Results>
|
||||
struct function_traits<void(Result<_Results...>, _Args...)>
|
||||
: public function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
struct function_traits<void(Result<_Results...>, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = true;
|
||||
using async_result_t = Result<_Results...>;
|
||||
};
|
||||
|
||||
template <typename... _Args, typename... _Results>
|
||||
struct function_traits<void(Result<_Results...>&&, _Args...)>
|
||||
: public function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
struct function_traits<void(Result<_Results...>&&, _Args...)> : function_traits_base<std::tuple<_Results...>, _Args...>
|
||||
{
|
||||
static constexpr bool is_async = true;
|
||||
using async_result_t = Result<_Results...>;
|
||||
};
|
||||
|
||||
template <typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(*)(_Args...)>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
struct function_traits<_ReturnType(*)(_Args...)> : function_traits<_ReturnType(_Args...)>
|
||||
{};
|
||||
|
||||
template <typename _ClassType, typename _ReturnType, typename... _Args>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...)>
|
||||
: public function_traits<_ReturnType(_Args...)>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...)> : 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...)>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const> : 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...)>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) volatile> : 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...)>
|
||||
struct function_traits<_ReturnType(_ClassType::*)(_Args...) const volatile> : function_traits<_ReturnType(_Args...)>
|
||||
{
|
||||
typedef const volatile _ClassType& owner_type;
|
||||
};
|
||||
|
||||
template <typename FunctionType>
|
||||
struct function_traits<std::function<FunctionType>>
|
||||
: public function_traits<FunctionType>
|
||||
struct function_traits<std::function<FunctionType>> : function_traits<FunctionType>
|
||||
{};
|
||||
|
||||
template <class _Function>
|
||||
@@ -621,45 +513,33 @@ namespace sdbus {
|
||||
template <typename _Function>
|
||||
using tuple_of_function_output_arg_types_t = typename tuple_of_function_output_arg_types<_Function>::type;
|
||||
|
||||
template <typename _Type>
|
||||
struct aggregate_signature
|
||||
template <typename _Function>
|
||||
struct signature_of_function_input_arguments : signature_of<tuple_of_function_input_arg_types_t<_Function>>
|
||||
{
|
||||
static const std::string str()
|
||||
static std::string value_as_string()
|
||||
{
|
||||
return signature_of<std::decay_t<_Type>>::str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... _Types>
|
||||
struct aggregate_signature<std::tuple<_Types...>>
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
std::string signature;
|
||||
(void)(signature += ... += signature_of<std::decay_t<_Types>>::str());
|
||||
return signature;
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_input_arg_types_t<_Function>>);
|
||||
return signature.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
struct signature_of_function_input_arguments
|
||||
inline auto signature_of_function_input_arguments_v = signature_of_function_input_arguments<_Function>::value_as_string();
|
||||
|
||||
template <typename _Function>
|
||||
struct signature_of_function_output_arguments : signature_of<tuple_of_function_output_arg_types_t<_Function>>
|
||||
{
|
||||
static const std::string str()
|
||||
static std::string value_as_string()
|
||||
{
|
||||
return aggregate_signature<tuple_of_function_input_arg_types_t<_Function>>::str();
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<tuple_of_function_output_arg_types_t<_Function>>);
|
||||
return signature.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Function>
|
||||
struct signature_of_function_output_arguments
|
||||
{
|
||||
static const std::string str()
|
||||
{
|
||||
return aggregate_signature<tuple_of_function_output_arg_types_t<_Function>>::str();
|
||||
}
|
||||
};
|
||||
|
||||
inline auto signature_of_function_output_arguments_v = signature_of_function_output_arguments<_Function>::value_as_string();
|
||||
|
||||
// std::future stuff for return values of async calls
|
||||
template <typename... _Args> struct future_return
|
||||
{
|
||||
typedef std::tuple<_Args...> type;
|
||||
@@ -678,7 +558,6 @@ namespace sdbus {
|
||||
template <typename... _Args>
|
||||
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;
|
||||
@@ -687,7 +566,6 @@ namespace sdbus {
|
||||
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>
|
||||
@@ -753,6 +631,26 @@ namespace sdbus {
|
||||
, std::forward<_Tuple>(t)
|
||||
, std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>{} );
|
||||
}
|
||||
|
||||
// Convenient concatenation of arrays
|
||||
template <typename _T, std::size_t _N1, std::size_t _N2>
|
||||
constexpr std::array<_T, _N1 + _N2> operator+(std::array<_T, _N1> lhs, std::array<_T, _N2> rhs)
|
||||
{
|
||||
std::array<_T, _N1 + _N2> result{};
|
||||
std::size_t index = 0;
|
||||
|
||||
for (auto& el : lhs) {
|
||||
result[index] = std::move(el);
|
||||
++index;
|
||||
}
|
||||
for (auto& el : rhs) {
|
||||
result[index] = std::move(el);
|
||||
++index;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDBUS_CXX_TYPETRAITS_H_ */
|
||||
|
||||
@@ -57,10 +57,9 @@ namespace sdbus {
|
||||
Variant();
|
||||
|
||||
template <typename _ValueType>
|
||||
explicit Variant(const _ValueType& value)
|
||||
: Variant()
|
||||
explicit Variant(const _ValueType& value) : Variant()
|
||||
{
|
||||
msg_.openVariant(signature_of<_ValueType>::str());
|
||||
msg_.openVariant<_ValueType>();
|
||||
msg_ << value;
|
||||
msg_.closeVariant();
|
||||
msg_.seal();
|
||||
@@ -79,7 +78,8 @@ namespace sdbus {
|
||||
{
|
||||
_ValueType val;
|
||||
msg_.rewind(false);
|
||||
msg_.enterVariant(signature_of<_ValueType>::str());
|
||||
|
||||
msg_.enterVariant<_ValueType>();
|
||||
msg_ >> val;
|
||||
msg_.exitVariant();
|
||||
return val;
|
||||
@@ -104,7 +104,8 @@ namespace sdbus {
|
||||
template <typename _Type>
|
||||
bool containsValueOfType() const
|
||||
{
|
||||
return signature_of<_Type>::str() == peekValueType();
|
||||
constexpr auto signature = as_null_terminated(signature_of_v<_Type>);
|
||||
return signature.data() == peekValueType();
|
||||
}
|
||||
|
||||
bool isEmpty() const;
|
||||
@@ -134,15 +135,12 @@ namespace sdbus {
|
||||
public:
|
||||
using std::tuple<_ValueTypes...>::tuple;
|
||||
|
||||
// Disable constructor if an older then 7.1.0 version of GCC is used
|
||||
#if !((defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !(__GNUC__ > 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 0)))))
|
||||
Struct() = default;
|
||||
|
||||
explicit Struct(const std::tuple<_ValueTypes...>& t)
|
||||
: std::tuple<_ValueTypes...>(t)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
template <std::size_t _I>
|
||||
auto& get()
|
||||
@@ -374,6 +372,16 @@ namespace sdbus {
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
/********************************************//**
|
||||
* @typedef DictEntry
|
||||
*
|
||||
* DictEntry is implemented as std::pair, a standard
|
||||
* value_type in STL(-like) associative containers.
|
||||
*
|
||||
***********************************************/
|
||||
template<typename _T1, typename _T2>
|
||||
using DictEntry = std::pair<_T1, _T2>;
|
||||
|
||||
}
|
||||
|
||||
template <size_t _I, typename... _ValueTypes>
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace sdbus {
|
||||
template <typename _Function>
|
||||
MethodVTableItem& MethodVTableItem::implementedAs(_Function&& callback)
|
||||
{
|
||||
inputSignature = signature_of_function_input_arguments<_Function>::str();
|
||||
outputSignature = signature_of_function_output_arguments<_Function>::str();
|
||||
inputSignature = signature_of_function_input_arguments_v<_Function>;
|
||||
outputSignature = signature_of_function_output_arguments_v<_Function>;
|
||||
callbackHandler = [callback = std::forward<_Function>(callback)](MethodCall call)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
@@ -142,7 +142,7 @@ namespace sdbus {
|
||||
template <typename... _Args>
|
||||
inline SignalVTableItem& SignalVTableItem::withParameters()
|
||||
{
|
||||
signature = signature_of_function_input_arguments<void(_Args...)>::str();
|
||||
signature = signature_of_function_input_arguments_v<void(_Args...)>;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace sdbus {
|
||||
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();
|
||||
signature = signature_of_function_output_arguments_v<_Function>;
|
||||
|
||||
getter = [callback = std::forward<_Function>(callback)](PropertyGetReply& reply)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ namespace sdbus {
|
||||
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();
|
||||
signature = signature_of_function_input_arguments_v<_Function>;
|
||||
|
||||
setter = [callback = std::forward<_Function>(callback)](PropertySetCall call)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user