Home | History | Annotate | Download | only in dbus
      1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
      6 #define LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
      7 
      8 // The main functionality provided by this header file is methods to serialize
      9 // native C++ data over D-Bus. This includes three major parts:
     10 // - Methods to get the D-Bus signature for a given C++ type:
     11 //     std::string GetDBusSignature<T>();
     12 // - Methods to write arbitrary C++ data to D-Bus MessageWriter:
     13 //     void AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
     14 //     void AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
     15 // - Methods to read arbitrary C++ data from D-Bus MessageReader:
     16 //     bool PopValueFromReader(dbus::MessageReader* reader, T* value);
     17 //     bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value);
     18 //
     19 // There are a number of overloads to handle C++ equivalents of basic D-Bus
     20 // types:
     21 //   D-Bus Type  | D-Bus Signature | Native C++ type
     22 //  --------------------------------------------------
     23 //   BYTE        |        y        |  uint8_t
     24 //   BOOL        |        b        |  bool
     25 //   INT16       |        n        |  int16_t
     26 //   UINT16      |        q        |  uint16_t
     27 //   INT32       |        i        |  int32_t (int)
     28 //   UINT32      |        u        |  uint32_t (unsigned)
     29 //   INT64       |        x        |  int64_t
     30 //   UINT64      |        t        |  uint64_t
     31 //   DOUBLE      |        d        |  double
     32 //   STRING      |        s        |  std::string
     33 //   OBJECT_PATH |        o        |  dbus::ObjectPath
     34 //   ARRAY       |        aT       |  std::vector<T>
     35 //   STRUCT      |       (UV)      |  std::pair<U,V>
     36 //               |     (UVW...)    |  std::tuple<U,V,W,...>
     37 //   DICT        |       a{KV}     |  std::map<K,V>
     38 //   VARIANT     |        v        |  brillo::Any
     39 //   UNIX_FD     |        h        |  base::ScopedFD
     40 //   SIGNATURE   |        g        |  (unsupported)
     41 //
     42 // Additional overloads/specialization can be provided for custom types.
     43 // In order to do that, provide overloads of AppendValueToWriter() and
     44 // PopValueFromReader() functions in brillo::dbus_utils namespace for the
     45 // CustomType. As well as a template specialization of DBusType<> for the same
     46 // CustomType. This specialization must provide three static functions:
     47 //  - static std::string GetSignature();
     48 //  - static void Write(dbus::MessageWriter* writer, const CustomType& value);
     49 //  - static bool Read(dbus::MessageReader* reader, CustomType* value);
     50 // See an example in DBusUtils.CustomStruct unit test in
     51 // brillo/dbus/data_serialization_unittest.cc.
     52 
     53 #include <map>
     54 #include <memory>
     55 #include <string>
     56 #include <tuple>
     57 #include <utility>
     58 #include <vector>
     59 
     60 #include <base/logging.h>
     61 #include <base/files/scoped_file.h>
     62 #include <brillo/brillo_export.h>
     63 #include <brillo/type_name_undecorate.h>
     64 #include <dbus/message.h>
     65 
     66 namespace google {
     67 namespace protobuf {
     68 class MessageLite;
     69 }  // namespace protobuf
     70 }  // namespace google
     71 
     72 namespace brillo {
     73 
     74 // Forward-declare only. Can't include any.h right now because it needs
     75 // AppendValueToWriter() declared below.
     76 class Any;
     77 
     78 namespace dbus_utils {
     79 
     80 // Base class for DBusType<T> for T not supported by D-Bus. This used to
     81 // implement IsTypeSupported<> below.
     82 struct Unsupported {};
     83 
     84 // Generic definition of DBusType<T> which will be specialized for particular
     85 // types later.
     86 // The second template parameter is used only in SFINAE situations to resolve
     87 // class hierarchy chains for protobuf-derived classes. This type is defaulted
     88 // to be 'void' in all other cases and simply ignored.
     89 // See DBusType specialization for google::protobuf::MessageLite below for more
     90 // detailed information.
     91 template<typename T, typename = void>
     92 struct DBusType : public Unsupported {};
     93 
     94 // A helper type trait to determine if all of the types listed in Types... are
     95 // supported by D-Bus. This is a generic forward-declaration which will be
     96 // specialized for different type combinations.
     97 template<typename... Types>
     98 struct IsTypeSupported;
     99 
    100 // Both T and the Types... must be supported for the complete set to be
    101 // supported.
    102 template<typename T, typename... Types>
    103 struct IsTypeSupported<T, Types...>
    104     : public std::integral_constant<
    105           bool,
    106           IsTypeSupported<T>::value && IsTypeSupported<Types...>::value> {};
    107 
    108 // For a single type T, check if DBusType<T> derives from Unsupported.
    109 // If it does, then the type is not supported by the D-Bus.
    110 template<typename T>
    111 struct IsTypeSupported<T>
    112     : public std::integral_constant<
    113           bool,
    114           !std::is_base_of<Unsupported, DBusType<T>>::value> {};
    115 
    116 // Empty set is not supported.
    117 template<>
    118 struct IsTypeSupported<> : public std::false_type {};
    119 
    120 //----------------------------------------------------------------------------
    121 // AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
    122 // Write the |value| of type T to D-Bus message.
    123 // Explicitly delete the overloads for scalar types that are not supported by
    124 // D-Bus.
    125 void AppendValueToWriter(dbus::MessageWriter* writer, char value) = delete;
    126 void AppendValueToWriter(dbus::MessageWriter* writer, float value) = delete;
    127 
    128 //----------------------------------------------------------------------------
    129 // PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
    130 // Reads the |value| of type T from D-Bus message.
    131 // Explicitly delete the overloads for scalar types that are not supported by
    132 // D-Bus.
    133 void PopValueFromReader(dbus::MessageReader* reader, char* value) = delete;
    134 void PopValueFromReader(dbus::MessageReader* reader, float* value) = delete;
    135 
    136 //----------------------------------------------------------------------------
    137 // Get D-Bus data signature from C++ data types.
    138 // Specializations of a generic GetDBusSignature<T>() provide signature strings
    139 // for native C++ types. This function is available only for type supported
    140 // by D-Bus.
    141 template<typename T>
    142 inline typename std::enable_if<IsTypeSupported<T>::value, std::string>::type
    143 GetDBusSignature() {
    144   return DBusType<T>::GetSignature();
    145 }
    146 
    147 namespace details {
    148 // Helper method used by the many overloads of PopValueFromReader().
    149 // If the current value in the reader is of Variant type, the method descends
    150 // into the Variant and updates the |*reader_ref| with the transient
    151 // |variant_reader| MessageReader instance passed in.
    152 // Returns false if it fails to descend into the Variant.
    153 inline bool DescendIntoVariantIfPresent(dbus::MessageReader** reader_ref,
    154                                         dbus::MessageReader* variant_reader) {
    155   if ((*reader_ref)->GetDataType() != dbus::Message::VARIANT)
    156     return true;
    157   if (!(*reader_ref)->PopVariant(variant_reader))
    158     return false;
    159   *reader_ref = variant_reader;
    160   return true;
    161 }
    162 
    163 // Helper method to format the type string of an array.
    164 // Essentially it adds "a" in front of |element_signature|.
    165 inline std::string GetArrayDBusSignature(const std::string& element_signature) {
    166   return DBUS_TYPE_ARRAY_AS_STRING + element_signature;
    167 }
    168 
    169 // Helper method to get a signature string for DICT_ENTRY.
    170 // Returns "{KV}", where "K" and "V" are the type signatures for types
    171 // KEY/VALUE. For example, GetDBusDictEntryType<std::string, int>() would return
    172 // "{si}".
    173 template<typename KEY, typename VALUE>
    174 inline std::string GetDBusDictEntryType() {
    175   return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING +
    176          GetDBusSignature<KEY>() + GetDBusSignature<VALUE>() +
    177          DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
    178 }
    179 
    180 }  // namespace details
    181 
    182 //=============================================================================
    183 // Specializations/overloads for AppendValueToWriter, PopValueFromReader and
    184 // DBusType<T> for various C++ types that can be serialized over D-Bus.
    185 
    186 // bool -----------------------------------------------------------------------
    187 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    188                                          bool value);
    189 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    190                                         bool* value);
    191 
    192 template<>
    193 struct DBusType<bool> {
    194   inline static std::string GetSignature() {
    195     return DBUS_TYPE_BOOLEAN_AS_STRING;
    196   }
    197   inline static void Write(dbus::MessageWriter* writer, bool value) {
    198     AppendValueToWriter(writer, value);
    199   }
    200   inline static bool Read(dbus::MessageReader* reader, bool* value) {
    201     return PopValueFromReader(reader, value);
    202   }
    203 };
    204 
    205 // uint8_t --------------------------------------------------------------------
    206 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    207                                          uint8_t value);
    208 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    209                                         uint8_t* value);
    210 
    211 template<>
    212 struct DBusType<uint8_t> {
    213   inline static std::string GetSignature() { return DBUS_TYPE_BYTE_AS_STRING; }
    214   inline static void Write(dbus::MessageWriter* writer, uint8_t value) {
    215     AppendValueToWriter(writer, value);
    216   }
    217   inline static bool Read(dbus::MessageReader* reader, uint8_t* value) {
    218     return PopValueFromReader(reader, value);
    219   }
    220 };
    221 
    222 // int16_t --------------------------------------------------------------------
    223 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    224                                          int16_t value);
    225 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    226                                         int16_t* value);
    227 
    228 template<>
    229 struct DBusType<int16_t> {
    230   inline static std::string GetSignature() { return DBUS_TYPE_INT16_AS_STRING; }
    231   inline static void Write(dbus::MessageWriter* writer, int16_t value) {
    232     AppendValueToWriter(writer, value);
    233   }
    234   inline static bool Read(dbus::MessageReader* reader, int16_t* value) {
    235     return PopValueFromReader(reader, value);
    236   }
    237 };
    238 
    239 // uint16_t -------------------------------------------------------------------
    240 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    241                                          uint16_t value);
    242 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    243                                         uint16_t* value);
    244 
    245 template<>
    246 struct DBusType<uint16_t> {
    247   inline static std::string GetSignature() {
    248     return DBUS_TYPE_UINT16_AS_STRING;
    249   }
    250   inline static void Write(dbus::MessageWriter* writer, uint16_t value) {
    251     AppendValueToWriter(writer, value);
    252   }
    253   inline static bool Read(dbus::MessageReader* reader, uint16_t* value) {
    254     return PopValueFromReader(reader, value);
    255   }
    256 };
    257 
    258 // int32_t --------------------------------------------------------------------
    259 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    260                                          int32_t value);
    261 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    262                                         int32_t* value);
    263 
    264 template<>
    265 struct DBusType<int32_t> {
    266   inline static std::string GetSignature() { return DBUS_TYPE_INT32_AS_STRING; }
    267   inline static void Write(dbus::MessageWriter* writer, int32_t value) {
    268     AppendValueToWriter(writer, value);
    269   }
    270   inline static bool Read(dbus::MessageReader* reader, int32_t* value) {
    271     return PopValueFromReader(reader, value);
    272   }
    273 };
    274 
    275 // uint32_t -------------------------------------------------------------------
    276 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    277                                          uint32_t value);
    278 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    279                                         uint32_t* value);
    280 
    281 template<>
    282 struct DBusType<uint32_t> {
    283   inline static std::string GetSignature() {
    284     return DBUS_TYPE_UINT32_AS_STRING;
    285   }
    286   inline static void Write(dbus::MessageWriter* writer, uint32_t value) {
    287     AppendValueToWriter(writer, value);
    288   }
    289   inline static bool Read(dbus::MessageReader* reader, uint32_t* value) {
    290     return PopValueFromReader(reader, value);
    291   }
    292 };
    293 
    294 // int64_t --------------------------------------------------------------------
    295 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    296                                          int64_t value);
    297 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    298                                         int64_t* value);
    299 
    300 template<>
    301 struct DBusType<int64_t> {
    302   inline static std::string GetSignature() { return DBUS_TYPE_INT64_AS_STRING; }
    303   inline static void Write(dbus::MessageWriter* writer, int64_t value) {
    304     AppendValueToWriter(writer, value);
    305   }
    306   inline static bool Read(dbus::MessageReader* reader, int64_t* value) {
    307     return PopValueFromReader(reader, value);
    308   }
    309 };
    310 
    311 // uint64_t -------------------------------------------------------------------
    312 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    313                                          uint64_t value);
    314 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    315                                         uint64_t* value);
    316 
    317 template<>
    318 struct DBusType<uint64_t> {
    319   inline static std::string GetSignature() {
    320     return DBUS_TYPE_UINT64_AS_STRING;
    321   }
    322   inline static void Write(dbus::MessageWriter* writer, uint64_t value) {
    323     AppendValueToWriter(writer, value);
    324   }
    325   inline static bool Read(dbus::MessageReader* reader, uint64_t* value) {
    326     return PopValueFromReader(reader, value);
    327   }
    328 };
    329 
    330 // double ---------------------------------------------------------------------
    331 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    332                                          double value);
    333 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    334                                         double* value);
    335 
    336 template<>
    337 struct DBusType<double> {
    338   inline static std::string GetSignature() {
    339     return DBUS_TYPE_DOUBLE_AS_STRING;
    340   }
    341   inline static void Write(dbus::MessageWriter* writer, double value) {
    342     AppendValueToWriter(writer, value);
    343   }
    344   inline static bool Read(dbus::MessageReader* reader, double* value) {
    345     return PopValueFromReader(reader, value);
    346   }
    347 };
    348 
    349 // std::string ----------------------------------------------------------------
    350 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    351                                          const std::string& value);
    352 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    353                                         std::string* value);
    354 
    355 template<>
    356 struct DBusType<std::string> {
    357   inline static std::string GetSignature() {
    358     return DBUS_TYPE_STRING_AS_STRING;
    359   }
    360   inline static void Write(dbus::MessageWriter* writer,
    361                            const std::string& value) {
    362     AppendValueToWriter(writer, value);
    363   }
    364   inline static bool Read(dbus::MessageReader* reader, std::string* value) {
    365     return PopValueFromReader(reader, value);
    366   }
    367 };
    368 
    369 // const char*
    370 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    371                                          const char* value);
    372 
    373 template<>
    374 struct DBusType<const char*> {
    375   inline static std::string GetSignature() {
    376     return DBUS_TYPE_STRING_AS_STRING;
    377   }
    378   inline static void Write(dbus::MessageWriter* writer, const char* value) {
    379     AppendValueToWriter(writer, value);
    380   }
    381 };
    382 
    383 // const char[]
    384 template<>
    385 struct DBusType<const char[]> {
    386   inline static std::string GetSignature() {
    387     return DBUS_TYPE_STRING_AS_STRING;
    388   }
    389   inline static void Write(dbus::MessageWriter* writer, const char* value) {
    390     AppendValueToWriter(writer, value);
    391   }
    392 };
    393 
    394 // dbus::ObjectPath -----------------------------------------------------------
    395 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    396                                          const dbus::ObjectPath& value);
    397 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    398                                         dbus::ObjectPath* value);
    399 
    400 template<>
    401 struct DBusType<dbus::ObjectPath> {
    402   inline static std::string GetSignature() {
    403     return DBUS_TYPE_OBJECT_PATH_AS_STRING;
    404   }
    405   inline static void Write(dbus::MessageWriter* writer,
    406                            const dbus::ObjectPath& value) {
    407     AppendValueToWriter(writer, value);
    408   }
    409   inline static bool Read(dbus::MessageReader* reader,
    410                           dbus::ObjectPath* value) {
    411     return PopValueFromReader(reader, value);
    412   }
    413 };
    414 
    415 // base::ScopedFD -------------------------------------------------------------
    416 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    417                                          const base::ScopedFD& value);
    418 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    419                                         base::ScopedFD* value);
    420 
    421 template<>
    422 struct DBusType<base::ScopedFD> {
    423   inline static std::string GetSignature() {
    424     return DBUS_TYPE_UNIX_FD_AS_STRING;
    425   }
    426   inline static void Write(dbus::MessageWriter* writer,
    427                            const base::ScopedFD& value) {
    428     AppendValueToWriter(writer, value);
    429   }
    430   inline static bool Read(dbus::MessageReader* reader,
    431                           base::ScopedFD* value) {
    432     return PopValueFromReader(reader, value);
    433   }
    434 };
    435 
    436 // brillo::Any --------------------------------------------------------------
    437 BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
    438                                          const brillo::Any& value);
    439 BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
    440                                         brillo::Any* value);
    441 
    442 template<>
    443 struct DBusType<brillo::Any> {
    444   inline static std::string GetSignature() {
    445     return DBUS_TYPE_VARIANT_AS_STRING;
    446   }
    447   inline static void Write(dbus::MessageWriter* writer,
    448                            const brillo::Any& value) {
    449     AppendValueToWriter(writer, value);
    450   }
    451   inline static bool Read(dbus::MessageReader* reader, brillo::Any* value) {
    452     return PopValueFromReader(reader, value);
    453   }
    454 };
    455 
    456 // std::vector = D-Bus ARRAY. -------------------------------------------------
    457 template<typename T, typename ALLOC>
    458 typename std::enable_if<IsTypeSupported<T>::value>::type AppendValueToWriter(
    459     dbus::MessageWriter* writer,
    460     const std::vector<T, ALLOC>& value) {
    461   dbus::MessageWriter array_writer(nullptr);
    462   writer->OpenArray(GetDBusSignature<T>(), &array_writer);
    463   for (const auto& element : value) {
    464     // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
    465     // binding to AppendValueToWriter() to the point of instantiation of this
    466     // template.
    467     DBusType<T>::Write(&array_writer, element);
    468   }
    469   writer->CloseContainer(&array_writer);
    470 }
    471 
    472 template<typename T, typename ALLOC>
    473 typename std::enable_if<IsTypeSupported<T>::value, bool>::type
    474 PopValueFromReader(dbus::MessageReader* reader, std::vector<T, ALLOC>* value) {
    475   dbus::MessageReader variant_reader(nullptr);
    476   dbus::MessageReader array_reader(nullptr);
    477   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
    478       !reader->PopArray(&array_reader))
    479     return false;
    480   value->clear();
    481   while (array_reader.HasMoreData()) {
    482     T data;
    483     // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
    484     // binding to PopValueFromReader() to the point of instantiation of this
    485     // template.
    486     if (!DBusType<T>::Read(&array_reader, &data))
    487       return false;
    488     value->push_back(std::move(data));
    489   }
    490   return true;
    491 }
    492 
    493 namespace details {
    494 // DBusArrayType<> is a helper base class for DBusType<vector<T>> that provides
    495 // GetSignature/Write/Read methods for T types that are supported by D-Bus
    496 // and not having those methods for types that are not supported by D-Bus.
    497 template<bool inner_type_supported, typename T, typename ALLOC>
    498 struct DBusArrayType {
    499   // Returns "aT", where "T" is the signature string for type T.
    500   inline static std::string GetSignature() {
    501     return GetArrayDBusSignature(GetDBusSignature<T>());
    502   }
    503   inline static void Write(dbus::MessageWriter* writer,
    504                            const std::vector<T, ALLOC>& value) {
    505     AppendValueToWriter(writer, value);
    506   }
    507   inline static bool Read(dbus::MessageReader* reader,
    508                           std::vector<T, ALLOC>* value) {
    509     return PopValueFromReader(reader, value);
    510   }
    511 };
    512 
    513 // Explicit specialization for unsupported type T.
    514 template<typename T, typename ALLOC>
    515 struct DBusArrayType<false, T, ALLOC> : public Unsupported {};
    516 
    517 }  // namespace details
    518 
    519 template<typename T, typename ALLOC>
    520 struct DBusType<std::vector<T, ALLOC>>
    521     : public details::DBusArrayType<IsTypeSupported<T>::value, T, ALLOC> {};
    522 
    523 // std::pair = D-Bus STRUCT with two elements. --------------------------------
    524 namespace details {
    525 
    526 // Helper class to get a D-Bus signature of a list of types.
    527 // For example, TupleTraits<int32_t, bool, std::string>::GetSignature() will
    528 // return "ibs".
    529 template<typename... Types>
    530 struct TupleTraits;
    531 
    532 template<typename FirstType, typename... RestOfTypes>
    533 struct TupleTraits<FirstType, RestOfTypes...> {
    534   static std::string GetSignature() {
    535     return GetDBusSignature<FirstType>() +
    536            TupleTraits<RestOfTypes...>::GetSignature();
    537   }
    538 };
    539 
    540 template<>
    541 struct TupleTraits<> {
    542   static std::string GetSignature() { return std::string{}; }
    543 };
    544 
    545 }  // namespace details
    546 
    547 template<typename... Types>
    548 inline std::string GetStructDBusSignature() {
    549   // Returns "(T...)", where "T..." is the signature strings for types T...
    550   return DBUS_STRUCT_BEGIN_CHAR_AS_STRING +
    551          details::TupleTraits<Types...>::GetSignature() +
    552          DBUS_STRUCT_END_CHAR_AS_STRING;
    553 }
    554 
    555 template<typename U, typename V>
    556 typename std::enable_if<IsTypeSupported<U, V>::value>::type AppendValueToWriter(
    557     dbus::MessageWriter* writer,
    558     const std::pair<U, V>& value) {
    559   dbus::MessageWriter struct_writer(nullptr);
    560   writer->OpenStruct(&struct_writer);
    561   // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
    562   // binding to AppendValueToWriter() to the point of instantiation of this
    563   // template.
    564   DBusType<U>::Write(&struct_writer, value.first);
    565   DBusType<V>::Write(&struct_writer, value.second);
    566   writer->CloseContainer(&struct_writer);
    567 }
    568 
    569 template<typename U, typename V>
    570 typename std::enable_if<IsTypeSupported<U, V>::value, bool>::type
    571 PopValueFromReader(dbus::MessageReader* reader, std::pair<U, V>* value) {
    572   dbus::MessageReader variant_reader(nullptr);
    573   dbus::MessageReader struct_reader(nullptr);
    574   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
    575       !reader->PopStruct(&struct_reader))
    576     return false;
    577   // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
    578   // binding to PopValueFromReader() to the point of instantiation of this
    579   // template.
    580   return DBusType<U>::Read(&struct_reader, &value->first) &&
    581          DBusType<V>::Read(&struct_reader, &value->second);
    582 }
    583 
    584 namespace details {
    585 
    586 // DBusArrayType<> is a helper base class for DBusType<pair<U, V>> that provides
    587 // GetSignature/Write/Read methods for types that are supported by D-Bus
    588 // and not having those methods for types that are not supported by D-Bus.
    589 template<bool inner_type_supported, typename U, typename V>
    590 struct DBusPairType {
    591   // Returns "(UV)", where "U" and "V" are the signature strings for types U, V.
    592   inline static std::string GetSignature() {
    593     return GetStructDBusSignature<U, V>();
    594   }
    595   inline static void Write(dbus::MessageWriter* writer,
    596                            const std::pair<U, V>& value) {
    597     AppendValueToWriter(writer, value);
    598   }
    599   inline static bool Read(dbus::MessageReader* reader, std::pair<U, V>* value) {
    600     return PopValueFromReader(reader, value);
    601   }
    602 };
    603 
    604 // Either U, or V, or both are not supported by D-Bus.
    605 template<typename U, typename V>
    606 struct DBusPairType<false, U, V> : public Unsupported {};
    607 
    608 }  // namespace details
    609 
    610 template<typename U, typename V>
    611 struct DBusType<std::pair<U, V>>
    612     : public details::DBusPairType<IsTypeSupported<U, V>::value, U, V> {};
    613 
    614 // std::tuple = D-Bus STRUCT with arbitrary number of members. ----------------
    615 namespace details {
    616 
    617 // TupleIterator<I, N, T...> is a helper class to iterate over all the elements
    618 // of a tuple<T...> from index I to N. TupleIterator<>::Read and ::Write methods
    619 // are called for each element of the tuple and iteration continues until I == N
    620 // in which case the specialization for I==N below stops the recursion.
    621 template<size_t I, size_t N, typename... T>
    622 struct TupleIterator {
    623   // Tuple is just a convenience alias to a tuple containing elements of type T.
    624   using Tuple = std::tuple<T...>;
    625   // ValueType is the type of the element at index I.
    626   using ValueType = typename std::tuple_element<I, Tuple>::type;
    627 
    628   // Write the tuple element at index I to D-Bus message.
    629   static void Write(dbus::MessageWriter* writer, const Tuple& value) {
    630     // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
    631     // binding to AppendValueToWriter() to the point of instantiation of this
    632     // template.
    633     DBusType<ValueType>::Write(writer, std::get<I>(value));
    634     TupleIterator<I + 1, N, T...>::Write(writer, value);
    635   }
    636 
    637   // Read the tuple element at index I from D-Bus message.
    638   static bool Read(dbus::MessageReader* reader, Tuple* value) {
    639     // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
    640     // binding to PopValueFromReader() to the point of instantiation of this
    641     // template.
    642     return DBusType<ValueType>::Read(reader, &std::get<I>(*value)) &&
    643            TupleIterator<I + 1, N, T...>::Read(reader, value);
    644   }
    645 };
    646 
    647 // Specialization to end the iteration when the index reaches the last element.
    648 template<size_t N, typename... T>
    649 struct TupleIterator<N, N, T...> {
    650   using Tuple = std::tuple<T...>;
    651   static void Write(dbus::MessageWriter* /* writer */,
    652                     const Tuple& /* value */) {}
    653   static bool Read(dbus::MessageReader* /* reader */,
    654                    Tuple* /* value */) { return true; }
    655 };
    656 
    657 }  // namespace details
    658 
    659 template<typename... T>
    660 typename std::enable_if<IsTypeSupported<T...>::value>::type AppendValueToWriter(
    661     dbus::MessageWriter* writer,
    662     const std::tuple<T...>& value) {
    663   dbus::MessageWriter struct_writer(nullptr);
    664   writer->OpenStruct(&struct_writer);
    665   details::TupleIterator<0, sizeof...(T), T...>::Write(&struct_writer, value);
    666   writer->CloseContainer(&struct_writer);
    667 }
    668 
    669 template<typename... T>
    670 typename std::enable_if<IsTypeSupported<T...>::value, bool>::type
    671 PopValueFromReader(dbus::MessageReader* reader, std::tuple<T...>* value) {
    672   dbus::MessageReader variant_reader(nullptr);
    673   dbus::MessageReader struct_reader(nullptr);
    674   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
    675       !reader->PopStruct(&struct_reader))
    676     return false;
    677   return details::TupleIterator<0, sizeof...(T), T...>::Read(&struct_reader,
    678                                                              value);
    679 }
    680 
    681 namespace details {
    682 
    683 // DBusTupleType<> is a helper base class for DBusType<tuple<T...>> that
    684 // provides GetSignature/Write/Read methods for types that are supported by
    685 // D-Bus and not having those methods for types that are not supported by D-Bus.
    686 template<bool inner_type_supported, typename... T>
    687 struct DBusTupleType {
    688   // Returns "(T...)", where "T..." are the signature strings for types T...
    689   inline static std::string GetSignature() {
    690     return GetStructDBusSignature<T...>();
    691   }
    692   inline static void Write(dbus::MessageWriter* writer,
    693                            const std::tuple<T...>& value) {
    694     AppendValueToWriter(writer, value);
    695   }
    696   inline static bool Read(dbus::MessageReader* reader,
    697                           std::tuple<T...>* value) {
    698     return PopValueFromReader(reader, value);
    699   }
    700 };
    701 
    702 // Some/all of types T... are not supported by D-Bus.
    703 template<typename... T>
    704 struct DBusTupleType<false, T...> : public Unsupported {};
    705 
    706 }  // namespace details
    707 
    708 template<typename... T>
    709 struct DBusType<std::tuple<T...>>
    710     : public details::DBusTupleType<IsTypeSupported<T...>::value, T...> {};
    711 
    712 // std::map = D-Bus ARRAY of DICT_ENTRY. --------------------------------------
    713 template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
    714 typename std::enable_if<IsTypeSupported<KEY, VALUE>::value>::type
    715 AppendValueToWriter(dbus::MessageWriter* writer,
    716                     const std::map<KEY, VALUE, PRED, ALLOC>& value) {
    717   dbus::MessageWriter dict_writer(nullptr);
    718   writer->OpenArray(details::GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
    719   for (const auto& pair : value) {
    720     dbus::MessageWriter entry_writer(nullptr);
    721     dict_writer.OpenDictEntry(&entry_writer);
    722     // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
    723     // binding to AppendValueToWriter() to the point of instantiation of this
    724     // template.
    725     DBusType<KEY>::Write(&entry_writer, pair.first);
    726     DBusType<VALUE>::Write(&entry_writer, pair.second);
    727     dict_writer.CloseContainer(&entry_writer);
    728   }
    729   writer->CloseContainer(&dict_writer);
    730 }
    731 
    732 template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
    733 typename std::enable_if<IsTypeSupported<KEY, VALUE>::value, bool>::type
    734 PopValueFromReader(dbus::MessageReader* reader,
    735                    std::map<KEY, VALUE, PRED, ALLOC>* value) {
    736   dbus::MessageReader variant_reader(nullptr);
    737   dbus::MessageReader array_reader(nullptr);
    738   if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
    739       !reader->PopArray(&array_reader))
    740     return false;
    741   value->clear();
    742   while (array_reader.HasMoreData()) {
    743     dbus::MessageReader dict_entry_reader(nullptr);
    744     if (!array_reader.PopDictEntry(&dict_entry_reader))
    745       return false;
    746     KEY key;
    747     VALUE data;
    748     // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
    749     // binding to PopValueFromReader() to the point of instantiation of this
    750     // template.
    751     if (!DBusType<KEY>::Read(&dict_entry_reader, &key) ||
    752         !DBusType<VALUE>::Read(&dict_entry_reader, &data))
    753       return false;
    754     value->emplace(std::move(key), std::move(data));
    755   }
    756   return true;
    757 }
    758 
    759 namespace details {
    760 
    761 // DBusArrayType<> is a helper base class for DBusType<map<K, V>> that provides
    762 // GetSignature/Write/Read methods for T types that are supported by D-Bus
    763 // and not having those methods for types that are not supported by D-Bus.
    764 template<bool inner_types_supported,
    765          typename KEY,
    766          typename VALUE,
    767          typename PRED,
    768          typename ALLOC>
    769 struct DBusMapType {
    770   // Returns "a{KV}", where "K" and "V" are the signature strings for types
    771   // KEY/VALUE.
    772   inline static std::string GetSignature() {
    773     return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
    774   }
    775   inline static void Write(dbus::MessageWriter* writer,
    776                            const std::map<KEY, VALUE, PRED, ALLOC>& value) {
    777     AppendValueToWriter(writer, value);
    778   }
    779   inline static bool Read(dbus::MessageReader* reader,
    780                           std::map<KEY, VALUE, PRED, ALLOC>* value) {
    781     return PopValueFromReader(reader, value);
    782   }
    783 };
    784 
    785 // Types KEY, VALUE or both are not supported by D-Bus.
    786 template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
    787 struct DBusMapType<false, KEY, VALUE, PRED, ALLOC> : public Unsupported {};
    788 
    789 }  // namespace details
    790 
    791 template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
    792 struct DBusType<std::map<KEY, VALUE, PRED, ALLOC>>
    793     : public details::DBusMapType<IsTypeSupported<KEY, VALUE>::value,
    794                                   KEY,
    795                                   VALUE,
    796                                   PRED,
    797                                   ALLOC> {};
    798 
    799 // google::protobuf::MessageLite = D-Bus ARRAY of BYTE ------------------------
    800 inline void AppendValueToWriter(dbus::MessageWriter* writer,
    801                                 const google::protobuf::MessageLite& value) {
    802   writer->AppendProtoAsArrayOfBytes(value);
    803 }
    804 
    805 inline bool PopValueFromReader(dbus::MessageReader* reader,
    806                                google::protobuf::MessageLite* value) {
    807   return reader->PopArrayOfBytesAsProto(value);
    808 }
    809 
    810 // is_protobuf_t<T> is a helper type trait to determine if type T derives from
    811 // google::protobuf::MessageLite.
    812 template<typename T>
    813 using is_protobuf = std::is_base_of<google::protobuf::MessageLite, T>;
    814 
    815 // Specialize DBusType<T> for classes that derive from protobuf::MessageLite.
    816 // Here we perform a partial specialization of DBusType<T> only for types
    817 // that derive from google::protobuf::MessageLite. This is done by employing
    818 // the second template parameter in DBusType and this basically relies on C++
    819 // SFINAE rules. "typename std::enable_if<is_protobuf<T>::value>::type" will
    820 // evaluate to "void" for classes T that descend from MessageLite and will be
    821 // an invalid construct for other types/classes which will automatically
    822 // remove this particular specialization from name resolution context.
    823 template<typename T>
    824 struct DBusType<T, typename std::enable_if<is_protobuf<T>::value>::type> {
    825   inline static std::string GetSignature() {
    826     return GetDBusSignature<std::vector<uint8_t>>();
    827   }
    828   inline static void Write(dbus::MessageWriter* writer, const T& value) {
    829     AppendValueToWriter(writer, value);
    830   }
    831   inline static bool Read(dbus::MessageReader* reader, T* value) {
    832     return PopValueFromReader(reader, value);
    833   }
    834 };
    835 
    836 //----------------------------------------------------------------------------
    837 // AppendValueToWriterAsVariant<T>(dbus::MessageWriter* writer, const T& value)
    838 // Write the |value| of type T to D-Bus message as a VARIANT.
    839 // This overload is provided only if T is supported by D-Bus.
    840 template<typename T>
    841 typename std::enable_if<IsTypeSupported<T>::value>::type
    842 AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const T& value) {
    843   std::string data_type = GetDBusSignature<T>();
    844   dbus::MessageWriter variant_writer(nullptr);
    845   writer->OpenVariant(data_type, &variant_writer);
    846   // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
    847   // binding to AppendValueToWriter() to the point of instantiation of this
    848   // template.
    849   DBusType<T>::Write(&variant_writer, value);
    850   writer->CloseContainer(&variant_writer);
    851 }
    852 
    853 // Special case: do not allow to write a Variant containing a Variant.
    854 // Just redirect to normal AppendValueToWriter().
    855 inline void AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
    856                                          const brillo::Any& value) {
    857   return AppendValueToWriter(writer, value);
    858 }
    859 
    860 //----------------------------------------------------------------------------
    861 // PopVariantValueFromReader<T>(dbus::MessageWriter* writer, T* value)
    862 // Reads a Variant containing the |value| of type T from D-Bus message.
    863 // Note that the generic PopValueFromReader<T>(...) can do this too.
    864 // This method is provided for two reasons:
    865 //   1. For API symmetry with AppendValueToWriter/AppendValueToWriterAsVariant.
    866 //   2. To be used when it is important to assert that the data was sent
    867 //      specifically as a Variant.
    868 // This overload is provided only if T is supported by D-Bus.
    869 template<typename T>
    870 typename std::enable_if<IsTypeSupported<T>::value, bool>::type
    871 PopVariantValueFromReader(dbus::MessageReader* reader, T* value) {
    872   dbus::MessageReader variant_reader(nullptr);
    873   if (!reader->PopVariant(&variant_reader))
    874     return false;
    875   // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
    876   // binding to PopValueFromReader() to the point of instantiation of this
    877   // template.
    878   return DBusType<T>::Read(&variant_reader, value);
    879 }
    880 
    881 // Special handling of request to read a Variant of Variant.
    882 inline bool PopVariantValueFromReader(dbus::MessageReader* reader, Any* value) {
    883   return PopValueFromReader(reader, value);
    884 }
    885 
    886 }  // namespace dbus_utils
    887 }  // namespace brillo
    888 
    889 #endif  // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
    890