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