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