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