blob: 83f397e3446adf34090209398635c7ce3536d310 [file] [log] [blame] [edit]
// Copyright 2014 The ChromiumOS Authors
// 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 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);
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <brillo/brillo_export.h>
#include <brillo/dbus/dbus_signature.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;
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.
// TODO(b/289932268): To catch actual errors, unwrapping should be done
// explicitly. Thus, this should be removed. Handling D-Bus variant should be
// done in other place explicitly.
BRILLO_EXPORT bool DescendIntoVariantIfPresent(
::dbus::MessageReader** reader_ref,
::dbus::MessageReader* variant_reader,
bool for_any = false);
} // 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 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 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 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 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 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 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 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 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 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 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 void Write(::dbus::MessageWriter* writer, const char* value) {
AppendValueToWriter(writer, value);
}
};
// const char[]
template <>
struct DBusType<const char[]> {
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 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);
}
};
// base::ScopedFD -------------------------------------------------------------
BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer,
const base::ScopedFD& value);
BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader,
base::ScopedFD* value);
template <>
struct DBusType<base::ScopedFD> {
inline static void Write(::dbus::MessageWriter* writer,
const base::ScopedFD& value) {
AppendValueToWriter(writer, value);
}
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 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 array_reader(nullptr);
if (!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
// 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 {
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. --------------------------------
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 struct_reader(nullptr);
if (!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
// 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 {
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 struct_reader(nullptr);
if (!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 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 {
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(internal::StrJoin("{", DBusSignature<KEY>::kValue,
DBusSignature<VALUE>::kValue, "}")
.data(),
&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 array_reader(nullptr);
if (!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
// 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 {
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 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) {
::dbus::MessageWriter variant_writer(nullptr);
writer->OpenVariant(GetDBusSignature<T>(), &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);
}
// Returns the type to store the D-Bus argument value.
// In-arg type is const T&, while out-arg type is T*.
// They will be converted into T.
template <typename T>
using StorageType = std::decay_t<std::remove_pointer_t<T>>;
// Reads the D-Bus arguments from |reader| to each |args| in order.
// Returns true on success, including there's no arguments remaining.
template <typename... Args>
bool ReadDBusArgs(dbus::MessageReader* reader, Args*... args) {
return (DBusType<std::decay_t<Args>>::Read(reader, args) && ...) &&
!reader->HasMoreData();
}
// Taking a tuple of either 1) references to arguments, or 2) storages
// of arguments, then read the D-Bus arguments to there.
template <typename Tuple>
bool ApplyReadDBusArgs(dbus::MessageReader* reader, Tuple&& tuple) {
return std::apply(
[reader](auto&&... in_args) { return ReadDBusArgs(reader, &in_args...); },
std::forward<Tuple>(tuple));
}
// Writes the D-Bus arguments to |writer| in order.
template <typename... Args>
void WriteDBusArgs(dbus::MessageWriter* writer, const Args&... args) {
(DBusType<std::decay_t<Args>>::Write(writer, args), ...);
}
// Currently, D-Bus arg reading function automatically unwraps variant,
// so even if the type is different from the spec, that may be read
// unexpectedly. That will be removed, and this is the flag for its
// safer migration. See also b/289932268.
enum class AutoVariantUnwrapState {
// Enabled the automatic variant unwrapping, i.e., the original state.
kEnabled,
// Still automatically unwrapped, but crash dump (without actual crash) will
// be reported when it happens. So, we can identify the cases in the world.
kDumpWithoutCrash,
// Disabled the automatic variant, which is the eventual state.
kDisabled,
};
BRILLO_EXPORT void SetAutoVariantUnwrapState(AutoVariantUnwrapState state);
BRILLO_EXPORT AutoVariantUnwrapState GetAutoVariantUnwrapState();
} // namespace dbus_utils
} // namespace brillo
#endif // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_