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