• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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