• 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        |  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