You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
901 lines
35 KiB
901 lines
35 KiB
// Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
|
|
#define LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
|
|
|
|
// The main functionality provided by this header file is methods to serialize
|
|
// native C++ data over D-Bus. This includes three major parts:
|
|
// - Methods to get the D-Bus signature for a given C++ type:
|
|
// std::string GetDBusSignature<T>();
|
|
// - Methods to write arbitrary C++ data to D-Bus MessageWriter:
|
|
// void AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
|
|
// void AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
|
|
// - Methods to read arbitrary C++ data from D-Bus MessageReader:
|
|
// bool PopValueFromReader(dbus::MessageReader* reader, T* value);
|
|
// bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value);
|
|
//
|
|
// There are a number of overloads to handle C++ equivalents of basic D-Bus
|
|
// types:
|
|
// D-Bus Type | D-Bus Signature | Native C++ type
|
|
// --------------------------------------------------
|
|
// BYTE | y | uint8_t
|
|
// BOOL | b | bool
|
|
// INT16 | n | int16_t
|
|
// UINT16 | q | uint16_t
|
|
// INT32 | i | int32_t (int)
|
|
// UINT32 | u | uint32_t (unsigned)
|
|
// INT64 | x | int64_t
|
|
// UINT64 | t | uint64_t
|
|
// DOUBLE | d | double
|
|
// STRING | s | std::string
|
|
// OBJECT_PATH | o | dbus::ObjectPath
|
|
// ARRAY | aT | std::vector<T>
|
|
// STRUCT | (UV) | std::pair<U,V>
|
|
// | (UVW...) | std::tuple<U,V,W,...>
|
|
// DICT | a{KV} | std::map<K,V>
|
|
// VARIANT | v | brillo::Any
|
|
// UNIX_FD | h | brillo::dbus_utils::FileDescriptor (write)
|
|
// | | base::ScopedFD (read)
|
|
// SIGNATURE | g | (unsupported)
|
|
//
|
|
// Additional overloads/specialization can be provided for custom types.
|
|
// In order to do that, provide overloads of AppendValueToWriter() and
|
|
// PopValueFromReader() functions in brillo::dbus_utils namespace for the
|
|
// CustomType. As well as a template specialization of DBusType<> for the same
|
|
// CustomType. This specialization must provide three static functions:
|
|
// - static std::string GetSignature();
|
|
// - static void Write(dbus::MessageWriter* writer, const CustomType& value);
|
|
// - static bool Read(dbus::MessageReader* reader, CustomType* value);
|
|
// See an example in DBusUtils.CustomStruct unit test in
|
|
// brillo/dbus/data_serialization_test.cc.
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <base/files/scoped_file.h>
|
|
#include <base/logging.h>
|
|
#include <base/files/scoped_file.h>
|
|
#include <brillo/brillo_export.h>
|
|
#include <brillo/dbus/file_descriptor.h>
|
|
#include <brillo/type_name_undecorate.h>
|
|
#include <dbus/message.h>
|
|
|
|
namespace google {
|
|
namespace protobuf {
|
|
class MessageLite;
|
|
} // namespace protobuf
|
|
} // namespace google
|
|
|
|
namespace brillo {
|
|
|
|
// Forward-declare only. Can't include any.h right now because it needs
|
|
// AppendValueToWriter() declared below.
|
|
class Any;
|
|
|
|
namespace dbus_utils {
|
|
|
|
// Base class for DBusType<T> for T not supported by D-Bus. This used to
|
|
// implement IsTypeSupported<> below.
|
|
struct Unsupported {};
|
|
|
|
// Generic definition of DBusType<T> which will be specialized for particular
|
|
// types later.
|
|
// The second template parameter is used only in SFINAE situations to resolve
|
|
// class hierarchy chains for protobuf-derived classes. This type is defaulted
|
|
// to be 'void' in all other cases and simply ignored.
|
|
// See DBusType specialization for google::protobuf::MessageLite below for more
|
|
// detailed information.
|
|
template<typename T, typename = void>
|
|
struct DBusType : public Unsupported {};
|
|
|
|
// A helper type trait to determine if all of the types listed in Types... are
|
|
// supported by D-Bus. This is a generic forward-declaration which will be
|
|
// specialized for different type combinations.
|
|
template<typename... Types>
|
|
struct IsTypeSupported;
|
|
|
|
// Both T and the Types... must be supported for the complete set to be
|
|
// supported.
|
|
template<typename T, typename... Types>
|
|
struct IsTypeSupported<T, Types...>
|
|
: public std::integral_constant<
|
|
bool,
|
|
IsTypeSupported<T>::value && IsTypeSupported<Types...>::value> {};
|
|
|
|
// For a single type T, check if DBusType<T> derives from Unsupported.
|
|
// If it does, then the type is not supported by the D-Bus.
|
|
template<typename T>
|
|
struct IsTypeSupported<T>
|
|
: public std::integral_constant<
|
|
bool,
|
|
!std::is_base_of<Unsupported, DBusType<T>>::value> {};
|
|
|
|
// Empty set is not supported.
|
|
template<>
|
|
struct IsTypeSupported<> : public std::false_type {};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
|
|
// Write the |value| of type T to D-Bus message.
|
|
// Explicitly delete the overloads for scalar types that are not supported by
|
|
// D-Bus.
|
|
void AppendValueToWriter(::dbus::MessageWriter* writer, char value) = delete;
|
|
void AppendValueToWriter(::dbus::MessageWriter* writer, float value) = delete;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
|
|
// Reads the |value| of type T from D-Bus message.
|
|
// Explicitly delete the overloads for scalar types that are not supported by
|
|
// D-Bus.
|
|
void PopValueFromReader(::dbus::MessageReader* reader, char* value) = delete;
|
|
void PopValueFromReader(::dbus::MessageReader* reader, float* value) = delete;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Get D-Bus data signature from C++ data types.
|
|
// Specializations of a generic GetDBusSignature<T>() provide signature strings
|
|
// for native C++ types. This function is available only for type supported
|
|
// by D-Bus.
|
|
template<typename T>
|
|
inline typename std::enable_if<IsTypeSupported<T>::value, std::string>::type
|
|
GetDBusSignature() {
|
|
return DBusType<T>::GetSignature();
|
|
}
|
|
|
|
namespace details {
|
|
// Helper method used by the many overloads of PopValueFromReader().
|
|
// If the current value in the reader is of Variant type, the method descends
|
|
// into the Variant and updates the |*reader_ref| with the transient
|
|
// |variant_reader| MessageReader instance passed in.
|
|
// Returns false if it fails to descend into the Variant.
|
|
inline bool DescendIntoVariantIfPresent(::dbus::MessageReader** reader_ref,
|
|
::dbus::MessageReader* variant_reader) {
|
|
if ((*reader_ref)->GetDataType() != ::dbus::Message::VARIANT)
|
|
return true;
|
|
if (!(*reader_ref)->PopVariant(variant_reader))
|
|
return false;
|
|
*reader_ref = variant_reader;
|
|
return true;
|
|
}
|
|
|
|
// Helper method to format the type string of an array.
|
|
// Essentially it adds "a" in front of |element_signature|.
|
|
inline std::string GetArrayDBusSignature(const std::string& element_signature) {
|
|
return DBUS_TYPE_ARRAY_AS_STRING + element_signature;
|
|
}
|
|
|
|
// Helper method to get a signature string for DICT_ENTRY.
|
|
// Returns "{KV}", where "K" and "V" are the type signatures for types
|
|
// KEY/VALUE. For example, GetDBusDictEntryType<std::string, int>() would return
|
|
// "{si}".
|
|
template<typename KEY, typename VALUE>
|
|
inline std::string GetDBusDictEntryType() {
|
|
return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING +
|
|
GetDBusSignature<KEY>() + GetDBusSignature<VALUE>() +
|
|
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
//=============================================================================
|
|
// Specializations/overloads for AppendValueToWriter, PopValueFromReader and
|
|
// DBusType<T> for various C++ types that can be serialized over D-Bus.
|
|
|
|
// bool -----------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
bool value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
bool* value);
|
|
|
|
template<>
|
|
struct DBusType<bool> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_BOOLEAN_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, bool value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, bool* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// uint8_t --------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
uint8_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
uint8_t* value);
|
|
|
|
template<>
|
|
struct DBusType<uint8_t> {
|
|
inline static std::string GetSignature() { return DBUS_TYPE_BYTE_AS_STRING; }
|
|
inline static void Write(::dbus::MessageWriter* writer, uint8_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, uint8_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// int16_t --------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
int16_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
int16_t* value);
|
|
|
|
template<>
|
|
struct DBusType<int16_t> {
|
|
inline static std::string GetSignature() { return DBUS_TYPE_INT16_AS_STRING; }
|
|
inline static void Write(::dbus::MessageWriter* writer, int16_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, int16_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// uint16_t -------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
uint16_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
uint16_t* value);
|
|
|
|
template<>
|
|
struct DBusType<uint16_t> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_UINT16_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, uint16_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, uint16_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// int32_t --------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
int32_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
int32_t* value);
|
|
|
|
template<>
|
|
struct DBusType<int32_t> {
|
|
inline static std::string GetSignature() { return DBUS_TYPE_INT32_AS_STRING; }
|
|
inline static void Write(::dbus::MessageWriter* writer, int32_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, int32_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// uint32_t -------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
uint32_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
uint32_t* value);
|
|
|
|
template<>
|
|
struct DBusType<uint32_t> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_UINT32_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, uint32_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, uint32_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// int64_t --------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
int64_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
int64_t* value);
|
|
|
|
template<>
|
|
struct DBusType<int64_t> {
|
|
inline static std::string GetSignature() { return DBUS_TYPE_INT64_AS_STRING; }
|
|
inline static void Write(::dbus::MessageWriter* writer, int64_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, int64_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// uint64_t -------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
uint64_t value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
uint64_t* value);
|
|
|
|
template<>
|
|
struct DBusType<uint64_t> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_UINT64_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, uint64_t value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, uint64_t* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// double ---------------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
double value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
double* value);
|
|
|
|
template<>
|
|
struct DBusType<double> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_DOUBLE_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, double value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, double* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// std::string ----------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const std::string& value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
std::string* value);
|
|
|
|
template<>
|
|
struct DBusType<std::string> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_STRING_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const std::string& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, std::string* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// const char*
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const char* value);
|
|
|
|
template<>
|
|
struct DBusType<const char*> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_STRING_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, const char* value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
};
|
|
|
|
// const char[]
|
|
template<>
|
|
struct DBusType<const char[]> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_STRING_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, const char* value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
};
|
|
|
|
// dbus::ObjectPath -----------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const ::dbus::ObjectPath& value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
::dbus::ObjectPath* value);
|
|
|
|
template <>
|
|
struct DBusType<::dbus::ObjectPath> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_OBJECT_PATH_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const ::dbus::ObjectPath& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
::dbus::ObjectPath* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// brillo::dbus_utils::FileDescriptor/base::ScopedFD --------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const FileDescriptor& value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
base::ScopedFD* value);
|
|
|
|
template<>
|
|
struct DBusType<FileDescriptor> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_UNIX_FD_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const FileDescriptor& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct DBusType<base::ScopedFD> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_UNIX_FD_AS_STRING;
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
base::ScopedFD* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// brillo::Any --------------------------------------------------------------
|
|
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const brillo::Any& value);
|
|
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
brillo::Any* value);
|
|
|
|
template<>
|
|
struct DBusType<brillo::Any> {
|
|
inline static std::string GetSignature() {
|
|
return DBUS_TYPE_VARIANT_AS_STRING;
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const brillo::Any& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, brillo::Any* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// std::vector = D-Bus ARRAY. -------------------------------------------------
|
|
template <typename T, typename ALLOC>
|
|
typename std::enable_if<IsTypeSupported<T>::value>::type AppendValueToWriter(
|
|
::dbus::MessageWriter* writer, const std::vector<T, ALLOC>& value) {
|
|
::dbus::MessageWriter array_writer(nullptr);
|
|
writer->OpenArray(GetDBusSignature<T>(), &array_writer);
|
|
for (const auto& element : value) {
|
|
// Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
|
|
// binding to AppendValueToWriter() to the point of instantiation of this
|
|
// template.
|
|
DBusType<T>::Write(&array_writer, element);
|
|
}
|
|
writer->CloseContainer(&array_writer);
|
|
}
|
|
|
|
template <typename T, typename ALLOC>
|
|
typename std::enable_if<IsTypeSupported<T>::value, bool>::type
|
|
PopValueFromReader(::dbus::MessageReader* reader,
|
|
std::vector<T, ALLOC>* value) {
|
|
::dbus::MessageReader variant_reader(nullptr);
|
|
::dbus::MessageReader array_reader(nullptr);
|
|
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
|
|
!reader->PopArray(&array_reader))
|
|
return false;
|
|
value->clear();
|
|
while (array_reader.HasMoreData()) {
|
|
T data;
|
|
// Use DBusType<T>::Read() instead of PopValueFromReader() to delay
|
|
// binding to PopValueFromReader() to the point of instantiation of this
|
|
// template.
|
|
if (!DBusType<T>::Read(&array_reader, &data))
|
|
return false;
|
|
value->push_back(std::move(data));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
namespace details {
|
|
// DBusArrayType<> is a helper base class for DBusType<vector<T>> that provides
|
|
// GetSignature/Write/Read methods for T types that are supported by D-Bus
|
|
// and not having those methods for types that are not supported by D-Bus.
|
|
template<bool inner_type_supported, typename T, typename ALLOC>
|
|
struct DBusArrayType {
|
|
// Returns "aT", where "T" is the signature string for type T.
|
|
inline static std::string GetSignature() {
|
|
return GetArrayDBusSignature(GetDBusSignature<T>());
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const std::vector<T, ALLOC>& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
std::vector<T, ALLOC>* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// Explicit specialization for unsupported type T.
|
|
template<typename T, typename ALLOC>
|
|
struct DBusArrayType<false, T, ALLOC> : public Unsupported {};
|
|
|
|
} // namespace details
|
|
|
|
template<typename T, typename ALLOC>
|
|
struct DBusType<std::vector<T, ALLOC>>
|
|
: public details::DBusArrayType<IsTypeSupported<T>::value, T, ALLOC> {};
|
|
|
|
// std::pair = D-Bus STRUCT with two elements. --------------------------------
|
|
namespace details {
|
|
|
|
// Helper class to get a D-Bus signature of a list of types.
|
|
// For example, TupleTraits<int32_t, bool, std::string>::GetSignature() will
|
|
// return "ibs".
|
|
template<typename... Types>
|
|
struct TupleTraits;
|
|
|
|
template<typename FirstType, typename... RestOfTypes>
|
|
struct TupleTraits<FirstType, RestOfTypes...> {
|
|
static std::string GetSignature() {
|
|
return GetDBusSignature<FirstType>() +
|
|
TupleTraits<RestOfTypes...>::GetSignature();
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct TupleTraits<> {
|
|
static std::string GetSignature() { return std::string{}; }
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
template<typename... Types>
|
|
inline std::string GetStructDBusSignature() {
|
|
// Returns "(T...)", where "T..." is the signature strings for types T...
|
|
return DBUS_STRUCT_BEGIN_CHAR_AS_STRING +
|
|
details::TupleTraits<Types...>::GetSignature() +
|
|
DBUS_STRUCT_END_CHAR_AS_STRING;
|
|
}
|
|
|
|
template <typename U, typename V>
|
|
typename std::enable_if<IsTypeSupported<U, V>::value>::type AppendValueToWriter(
|
|
::dbus::MessageWriter* writer, const std::pair<U, V>& value) {
|
|
::dbus::MessageWriter struct_writer(nullptr);
|
|
writer->OpenStruct(&struct_writer);
|
|
// Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
|
|
// binding to AppendValueToWriter() to the point of instantiation of this
|
|
// template.
|
|
DBusType<U>::Write(&struct_writer, value.first);
|
|
DBusType<V>::Write(&struct_writer, value.second);
|
|
writer->CloseContainer(&struct_writer);
|
|
}
|
|
|
|
template <typename U, typename V>
|
|
typename std::enable_if<IsTypeSupported<U, V>::value, bool>::type
|
|
PopValueFromReader(::dbus::MessageReader* reader, std::pair<U, V>* value) {
|
|
::dbus::MessageReader variant_reader(nullptr);
|
|
::dbus::MessageReader struct_reader(nullptr);
|
|
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
|
|
!reader->PopStruct(&struct_reader))
|
|
return false;
|
|
// Use DBusType<T>::Read() instead of PopValueFromReader() to delay
|
|
// binding to PopValueFromReader() to the point of instantiation of this
|
|
// template.
|
|
return DBusType<U>::Read(&struct_reader, &value->first) &&
|
|
DBusType<V>::Read(&struct_reader, &value->second);
|
|
}
|
|
|
|
namespace details {
|
|
|
|
// DBusArrayType<> is a helper base class for DBusType<pair<U, V>> that provides
|
|
// GetSignature/Write/Read methods for types that are supported by D-Bus
|
|
// and not having those methods for types that are not supported by D-Bus.
|
|
template<bool inner_type_supported, typename U, typename V>
|
|
struct DBusPairType {
|
|
// Returns "(UV)", where "U" and "V" are the signature strings for types U, V.
|
|
inline static std::string GetSignature() {
|
|
return GetStructDBusSignature<U, V>();
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const std::pair<U, V>& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
std::pair<U, V>* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// Either U, or V, or both are not supported by D-Bus.
|
|
template<typename U, typename V>
|
|
struct DBusPairType<false, U, V> : public Unsupported {};
|
|
|
|
} // namespace details
|
|
|
|
template<typename U, typename V>
|
|
struct DBusType<std::pair<U, V>>
|
|
: public details::DBusPairType<IsTypeSupported<U, V>::value, U, V> {};
|
|
|
|
// std::tuple = D-Bus STRUCT with arbitrary number of members. ----------------
|
|
namespace details {
|
|
|
|
// TupleIterator<I, N, T...> is a helper class to iterate over all the elements
|
|
// of a tuple<T...> from index I to N. TupleIterator<>::Read and ::Write methods
|
|
// are called for each element of the tuple and iteration continues until I == N
|
|
// in which case the specialization for I==N below stops the recursion.
|
|
template<size_t I, size_t N, typename... T>
|
|
struct TupleIterator {
|
|
// Tuple is just a convenience alias to a tuple containing elements of type T.
|
|
using Tuple = std::tuple<T...>;
|
|
// ValueType is the type of the element at index I.
|
|
using ValueType = typename std::tuple_element<I, Tuple>::type;
|
|
|
|
// Write the tuple element at index I to D-Bus message.
|
|
static void Write(::dbus::MessageWriter* writer, const Tuple& value) {
|
|
// Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
|
|
// binding to AppendValueToWriter() to the point of instantiation of this
|
|
// template.
|
|
DBusType<ValueType>::Write(writer, std::get<I>(value));
|
|
TupleIterator<I + 1, N, T...>::Write(writer, value);
|
|
}
|
|
|
|
// Read the tuple element at index I from D-Bus message.
|
|
static bool Read(::dbus::MessageReader* reader, Tuple* value) {
|
|
// Use DBusType<T>::Read() instead of PopValueFromReader() to delay
|
|
// binding to PopValueFromReader() to the point of instantiation of this
|
|
// template.
|
|
return DBusType<ValueType>::Read(reader, &std::get<I>(*value)) &&
|
|
TupleIterator<I + 1, N, T...>::Read(reader, value);
|
|
}
|
|
};
|
|
|
|
// Specialization to end the iteration when the index reaches the last element.
|
|
template<size_t N, typename... T>
|
|
struct TupleIterator<N, N, T...> {
|
|
using Tuple = std::tuple<T...>;
|
|
static void Write(::dbus::MessageWriter* /* writer */,
|
|
const Tuple& /* value */) {}
|
|
static bool Read(::dbus::MessageReader* /* reader */, Tuple* /* value */) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
template <typename... T>
|
|
typename std::enable_if<IsTypeSupported<T...>::value>::type AppendValueToWriter(
|
|
::dbus::MessageWriter* writer, const std::tuple<T...>& value) {
|
|
::dbus::MessageWriter struct_writer(nullptr);
|
|
writer->OpenStruct(&struct_writer);
|
|
details::TupleIterator<0, sizeof...(T), T...>::Write(&struct_writer, value);
|
|
writer->CloseContainer(&struct_writer);
|
|
}
|
|
|
|
template <typename... T>
|
|
typename std::enable_if<IsTypeSupported<T...>::value, bool>::type
|
|
PopValueFromReader(::dbus::MessageReader* reader, std::tuple<T...>* value) {
|
|
::dbus::MessageReader variant_reader(nullptr);
|
|
::dbus::MessageReader struct_reader(nullptr);
|
|
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
|
|
!reader->PopStruct(&struct_reader))
|
|
return false;
|
|
return details::TupleIterator<0, sizeof...(T), T...>::Read(&struct_reader,
|
|
value);
|
|
}
|
|
|
|
namespace details {
|
|
|
|
// DBusTupleType<> is a helper base class for DBusType<tuple<T...>> that
|
|
// provides GetSignature/Write/Read methods for types that are supported by
|
|
// D-Bus and not having those methods for types that are not supported by D-Bus.
|
|
template<bool inner_type_supported, typename... T>
|
|
struct DBusTupleType {
|
|
// Returns "(T...)", where "T..." are the signature strings for types T...
|
|
inline static std::string GetSignature() {
|
|
return GetStructDBusSignature<T...>();
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const std::tuple<T...>& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
std::tuple<T...>* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// Some/all of types T... are not supported by D-Bus.
|
|
template<typename... T>
|
|
struct DBusTupleType<false, T...> : public Unsupported {};
|
|
|
|
} // namespace details
|
|
|
|
template<typename... T>
|
|
struct DBusType<std::tuple<T...>>
|
|
: public details::DBusTupleType<IsTypeSupported<T...>::value, T...> {};
|
|
|
|
// std::map = D-Bus ARRAY of DICT_ENTRY. --------------------------------------
|
|
template <typename KEY, typename VALUE, typename PRED, typename ALLOC>
|
|
typename std::enable_if<IsTypeSupported<KEY, VALUE>::value>::type
|
|
AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const std::map<KEY, VALUE, PRED, ALLOC>& value) {
|
|
::dbus::MessageWriter dict_writer(nullptr);
|
|
writer->OpenArray(details::GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
|
|
for (const auto& pair : value) {
|
|
::dbus::MessageWriter entry_writer(nullptr);
|
|
dict_writer.OpenDictEntry(&entry_writer);
|
|
// Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
|
|
// binding to AppendValueToWriter() to the point of instantiation of this
|
|
// template.
|
|
DBusType<KEY>::Write(&entry_writer, pair.first);
|
|
DBusType<VALUE>::Write(&entry_writer, pair.second);
|
|
dict_writer.CloseContainer(&entry_writer);
|
|
}
|
|
writer->CloseContainer(&dict_writer);
|
|
}
|
|
|
|
template <typename KEY, typename VALUE, typename PRED, typename ALLOC>
|
|
typename std::enable_if<IsTypeSupported<KEY, VALUE>::value, bool>::type
|
|
PopValueFromReader(::dbus::MessageReader* reader,
|
|
std::map<KEY, VALUE, PRED, ALLOC>* value) {
|
|
::dbus::MessageReader variant_reader(nullptr);
|
|
::dbus::MessageReader array_reader(nullptr);
|
|
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
|
|
!reader->PopArray(&array_reader))
|
|
return false;
|
|
value->clear();
|
|
while (array_reader.HasMoreData()) {
|
|
::dbus::MessageReader dict_entry_reader(nullptr);
|
|
if (!array_reader.PopDictEntry(&dict_entry_reader))
|
|
return false;
|
|
KEY key;
|
|
VALUE data;
|
|
// Use DBusType<T>::Read() instead of PopValueFromReader() to delay
|
|
// binding to PopValueFromReader() to the point of instantiation of this
|
|
// template.
|
|
if (!DBusType<KEY>::Read(&dict_entry_reader, &key) ||
|
|
!DBusType<VALUE>::Read(&dict_entry_reader, &data))
|
|
return false;
|
|
value->emplace(std::move(key), std::move(data));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
namespace details {
|
|
|
|
// DBusArrayType<> is a helper base class for DBusType<map<K, V>> that provides
|
|
// GetSignature/Write/Read methods for T types that are supported by D-Bus
|
|
// and not having those methods for types that are not supported by D-Bus.
|
|
template<bool inner_types_supported,
|
|
typename KEY,
|
|
typename VALUE,
|
|
typename PRED,
|
|
typename ALLOC>
|
|
struct DBusMapType {
|
|
// Returns "a{KV}", where "K" and "V" are the signature strings for types
|
|
// KEY/VALUE.
|
|
inline static std::string GetSignature() {
|
|
return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer,
|
|
const std::map<KEY, VALUE, PRED, ALLOC>& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader,
|
|
std::map<KEY, VALUE, PRED, ALLOC>* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
// Types KEY, VALUE or both are not supported by D-Bus.
|
|
template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
|
|
struct DBusMapType<false, KEY, VALUE, PRED, ALLOC> : public Unsupported {};
|
|
|
|
} // namespace details
|
|
|
|
template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
|
|
struct DBusType<std::map<KEY, VALUE, PRED, ALLOC>>
|
|
: public details::DBusMapType<IsTypeSupported<KEY, VALUE>::value,
|
|
KEY,
|
|
VALUE,
|
|
PRED,
|
|
ALLOC> {};
|
|
|
|
// google::protobuf::MessageLite = D-Bus ARRAY of BYTE ------------------------
|
|
inline void AppendValueToWriter(::dbus::MessageWriter* writer,
|
|
const google::protobuf::MessageLite& value) {
|
|
writer->AppendProtoAsArrayOfBytes(value);
|
|
}
|
|
|
|
inline bool PopValueFromReader(::dbus::MessageReader* reader,
|
|
google::protobuf::MessageLite* value) {
|
|
return reader->PopArrayOfBytesAsProto(value);
|
|
}
|
|
|
|
// is_protobuf_t<T> is a helper type trait to determine if type T derives from
|
|
// google::protobuf::MessageLite.
|
|
template<typename T>
|
|
using is_protobuf = std::is_base_of<google::protobuf::MessageLite, T>;
|
|
|
|
// Specialize DBusType<T> for classes that derive from protobuf::MessageLite.
|
|
// Here we perform a partial specialization of DBusType<T> only for types
|
|
// that derive from google::protobuf::MessageLite. This is done by employing
|
|
// the second template parameter in DBusType and this basically relies on C++
|
|
// SFINAE rules. "typename std::enable_if<is_protobuf<T>::value>::type" will
|
|
// evaluate to "void" for classes T that descend from MessageLite and will be
|
|
// an invalid construct for other types/classes which will automatically
|
|
// remove this particular specialization from name resolution context.
|
|
template<typename T>
|
|
struct DBusType<T, typename std::enable_if<is_protobuf<T>::value>::type> {
|
|
inline static std::string GetSignature() {
|
|
return GetDBusSignature<std::vector<uint8_t>>();
|
|
}
|
|
inline static void Write(::dbus::MessageWriter* writer, const T& value) {
|
|
AppendValueToWriter(writer, value);
|
|
}
|
|
inline static bool Read(::dbus::MessageReader* reader, T* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// AppendValueToWriterAsVariant<T>(::dbus::MessageWriter* writer, const T&
|
|
// value) Write the |value| of type T to D-Bus message as a VARIANT. This
|
|
// overload is provided only if T is supported by D-Bus.
|
|
template <typename T>
|
|
typename std::enable_if<IsTypeSupported<T>::value>::type
|
|
AppendValueToWriterAsVariant(::dbus::MessageWriter* writer, const T& value) {
|
|
std::string data_type = GetDBusSignature<T>();
|
|
::dbus::MessageWriter variant_writer(nullptr);
|
|
writer->OpenVariant(data_type, &variant_writer);
|
|
// Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
|
|
// binding to AppendValueToWriter() to the point of instantiation of this
|
|
// template.
|
|
DBusType<T>::Write(&variant_writer, value);
|
|
writer->CloseContainer(&variant_writer);
|
|
}
|
|
|
|
// Special case: do not allow to write a Variant containing a Variant.
|
|
// Just redirect to normal AppendValueToWriter().
|
|
inline void AppendValueToWriterAsVariant(::dbus::MessageWriter* writer,
|
|
const brillo::Any& value) {
|
|
return AppendValueToWriter(writer, value);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// PopVariantValueFromReader<T>(::dbus::MessageWriter* writer, T* value)
|
|
// Reads a Variant containing the |value| of type T from D-Bus message.
|
|
// Note that the generic PopValueFromReader<T>(...) can do this too.
|
|
// This method is provided for two reasons:
|
|
// 1. For API symmetry with AppendValueToWriter/AppendValueToWriterAsVariant.
|
|
// 2. To be used when it is important to assert that the data was sent
|
|
// specifically as a Variant.
|
|
// This overload is provided only if T is supported by D-Bus.
|
|
template <typename T>
|
|
typename std::enable_if<IsTypeSupported<T>::value, bool>::type
|
|
PopVariantValueFromReader(::dbus::MessageReader* reader, T* value) {
|
|
::dbus::MessageReader variant_reader(nullptr);
|
|
if (!reader->PopVariant(&variant_reader))
|
|
return false;
|
|
// Use DBusType<T>::Read() instead of PopValueFromReader() to delay
|
|
// binding to PopValueFromReader() to the point of instantiation of this
|
|
// template.
|
|
return DBusType<T>::Read(&variant_reader, value);
|
|
}
|
|
|
|
// Special handling of request to read a Variant of Variant.
|
|
inline bool PopVariantValueFromReader(::dbus::MessageReader* reader,
|
|
Any* value) {
|
|
return PopValueFromReader(reader, value);
|
|
}
|
|
|
|
} // namespace dbus_utils
|
|
} // namespace brillo
|
|
|
|
#endif // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
|