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