// Copyright 2014 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_ #define LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_ // The main functionality provided by this header file is methods to serialize // native C++ data over D-Bus. This includes three major parts: // - Methods to get the D-Bus signature for a given C++ type: // std::string GetDBusSignature(); // - Methods to write arbitrary C++ data to D-Bus MessageWriter: // void AppendValueToWriter(dbus::MessageWriter* writer, const T& value); // void AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&); // - Methods to read arbitrary C++ data from D-Bus MessageReader: // bool PopValueFromReader(dbus::MessageReader* reader, T* value); // bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value); // // There are a number of overloads to handle C++ equivalents of basic D-Bus // types: // D-Bus Type | D-Bus Signature | Native C++ type // -------------------------------------------------- // BYTE | y | uint8_t // BOOL | b | bool // INT16 | n | int16_t // UINT16 | q | uint16_t // INT32 | i | int32_t (int) // UINT32 | u | uint32_t (unsigned) // INT64 | x | int64_t // UINT64 | t | uint64_t // DOUBLE | d | double // STRING | s | std::string // OBJECT_PATH | o | dbus::ObjectPath // ARRAY | aT | std::vector // STRUCT | (UV) | std::pair // | (UVW...) | std::tuple // DICT | a{KV} | std::map // VARIANT | v | brillo::Any // UNIX_FD | h | brillo::dbus_utils::FileDescriptor (write) // | | base::ScopedFD (read) // SIGNATURE | g | (unsupported) // // Additional overloads/specialization can be provided for custom types. // In order to do that, provide overloads of AppendValueToWriter() and // PopValueFromReader() functions in brillo::dbus_utils namespace for the // CustomType. As well as a template specialization of DBusType<> for the same // CustomType. This specialization must provide three static functions: // - static std::string GetSignature(); // - static void Write(dbus::MessageWriter* writer, const CustomType& value); // - static bool Read(dbus::MessageReader* reader, CustomType* value); // See an example in DBusUtils.CustomStruct unit test in // brillo/dbus/data_serialization_unittest.cc. #include #include #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { class MessageLite; } // namespace protobuf } // namespace google namespace brillo { // Forward-declare only. Can't include any.h right now because it needs // AppendValueToWriter() declared below. class Any; namespace dbus_utils { // Base class for DBusType for T not supported by D-Bus. This used to // implement IsTypeSupported<> below. struct Unsupported {}; // Generic definition of DBusType which will be specialized for particular // types later. // The second template parameter is used only in SFINAE situations to resolve // class hierarchy chains for protobuf-derived classes. This type is defaulted // to be 'void' in all other cases and simply ignored. // See DBusType specialization for google::protobuf::MessageLite below for more // detailed information. template struct DBusType : public Unsupported {}; // A helper type trait to determine if all of the types listed in Types... are // supported by D-Bus. This is a generic forward-declaration which will be // specialized for different type combinations. template struct IsTypeSupported; // Both T and the Types... must be supported for the complete set to be // supported. template struct IsTypeSupported : public std::integral_constant< bool, IsTypeSupported::value && IsTypeSupported::value> {}; // For a single type T, check if DBusType derives from Unsupported. // If it does, then the type is not supported by the D-Bus. template struct IsTypeSupported : public std::integral_constant< bool, !std::is_base_of>::value> {}; // Empty set is not supported. template<> struct IsTypeSupported<> : public std::false_type {}; //---------------------------------------------------------------------------- // AppendValueToWriter(dbus::MessageWriter* writer, const T& value) // Write the |value| of type T to D-Bus message. // Explicitly delete the overloads for scalar types that are not supported by // D-Bus. void AppendValueToWriter(dbus::MessageWriter* writer, char value) = delete; void AppendValueToWriter(dbus::MessageWriter* writer, float value) = delete; //---------------------------------------------------------------------------- // PopValueFromReader(dbus::MessageWriter* writer, T* value) // Reads the |value| of type T from D-Bus message. // Explicitly delete the overloads for scalar types that are not supported by // D-Bus. void PopValueFromReader(dbus::MessageReader* reader, char* value) = delete; void PopValueFromReader(dbus::MessageReader* reader, float* value) = delete; //---------------------------------------------------------------------------- // Get D-Bus data signature from C++ data types. // Specializations of a generic GetDBusSignature() provide signature strings // for native C++ types. This function is available only for type supported // by D-Bus. template inline typename std::enable_if::value, std::string>::type GetDBusSignature() { return DBusType::GetSignature(); } namespace details { // Helper method used by the many overloads of PopValueFromReader(). // If the current value in the reader is of Variant type, the method descends // into the Variant and updates the |*reader_ref| with the transient // |variant_reader| MessageReader instance passed in. // Returns false if it fails to descend into the Variant. inline bool DescendIntoVariantIfPresent(dbus::MessageReader** reader_ref, dbus::MessageReader* variant_reader) { if ((*reader_ref)->GetDataType() != dbus::Message::VARIANT) return true; if (!(*reader_ref)->PopVariant(variant_reader)) return false; *reader_ref = variant_reader; return true; } // Helper method to format the type string of an array. // Essentially it adds "a" in front of |element_signature|. inline std::string GetArrayDBusSignature(const std::string& element_signature) { return DBUS_TYPE_ARRAY_AS_STRING + element_signature; } // Helper method to get a signature string for DICT_ENTRY. // Returns "{KV}", where "K" and "V" are the type signatures for types // KEY/VALUE. For example, GetDBusDictEntryType() would return // "{si}". template inline std::string GetDBusDictEntryType() { return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + GetDBusSignature() + GetDBusSignature() + DBUS_DICT_ENTRY_END_CHAR_AS_STRING; } } // namespace details //============================================================================= // Specializations/overloads for AppendValueToWriter, PopValueFromReader and // DBusType for various C++ types that can be serialized over D-Bus. // bool ----------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, bool value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, bool* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_BOOLEAN_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, bool value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, bool* value) { return PopValueFromReader(reader, value); } }; // uint8_t -------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, uint8_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_BYTE_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, uint8_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, uint8_t* value) { return PopValueFromReader(reader, value); } }; // int16_t -------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, int16_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_INT16_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, int16_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, int16_t* value) { return PopValueFromReader(reader, value); } }; // uint16_t ------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, uint16_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_UINT16_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, uint16_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, uint16_t* value) { return PopValueFromReader(reader, value); } }; // int32_t -------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, int32_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_INT32_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, int32_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, int32_t* value) { return PopValueFromReader(reader, value); } }; // uint32_t ------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, uint32_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_UINT32_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, uint32_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, uint32_t* value) { return PopValueFromReader(reader, value); } }; // int64_t -------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, int64_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_INT64_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, int64_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, int64_t* value) { return PopValueFromReader(reader, value); } }; // uint64_t ------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, uint64_t* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_UINT64_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, uint64_t value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, uint64_t* value) { return PopValueFromReader(reader, value); } }; // double --------------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, double value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, double* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_DOUBLE_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, double value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, double* value) { return PopValueFromReader(reader, value); } }; // std::string ---------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, const std::string& value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, std::string* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_STRING_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const std::string& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, std::string* value) { return PopValueFromReader(reader, value); } }; // const char* BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, const char* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_STRING_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const char* value) { AppendValueToWriter(writer, value); } }; // const char[] template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_STRING_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const char* value) { AppendValueToWriter(writer, value); } }; // dbus::ObjectPath ----------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, const dbus::ObjectPath& value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, dbus::ObjectPath* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_OBJECT_PATH_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const dbus::ObjectPath& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, dbus::ObjectPath* value) { return PopValueFromReader(reader, value); } }; // brillo::dbus_utils::FileDescriptor/base::ScopedFD -------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, const FileDescriptor& value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, base::ScopedFD* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_UNIX_FD_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const FileDescriptor& value) { AppendValueToWriter(writer, value); } }; template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_UNIX_FD_AS_STRING; } inline static bool Read(dbus::MessageReader* reader, base::ScopedFD* value) { return PopValueFromReader(reader, value); } }; // brillo::Any -------------------------------------------------------------- BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer, const brillo::Any& value); BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value); template<> struct DBusType { inline static std::string GetSignature() { return DBUS_TYPE_VARIANT_AS_STRING; } inline static void Write(dbus::MessageWriter* writer, const brillo::Any& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, brillo::Any* value) { return PopValueFromReader(reader, value); } }; // std::vector = D-Bus ARRAY. ------------------------------------------------- template typename std::enable_if::value>::type AppendValueToWriter( dbus::MessageWriter* writer, const std::vector& value) { dbus::MessageWriter array_writer(nullptr); writer->OpenArray(GetDBusSignature(), &array_writer); for (const auto& element : value) { // Use DBusType::Write() instead of AppendValueToWriter() to delay // binding to AppendValueToWriter() to the point of instantiation of this // template. DBusType::Write(&array_writer, element); } writer->CloseContainer(&array_writer); } template typename std::enable_if::value, bool>::type PopValueFromReader(dbus::MessageReader* reader, std::vector* value) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader array_reader(nullptr); if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) || !reader->PopArray(&array_reader)) return false; value->clear(); while (array_reader.HasMoreData()) { T data; // Use DBusType::Read() instead of PopValueFromReader() to delay // binding to PopValueFromReader() to the point of instantiation of this // template. if (!DBusType::Read(&array_reader, &data)) return false; value->push_back(std::move(data)); } return true; } namespace details { // DBusArrayType<> is a helper base class for DBusType> that provides // GetSignature/Write/Read methods for T types that are supported by D-Bus // and not having those methods for types that are not supported by D-Bus. template struct DBusArrayType { // Returns "aT", where "T" is the signature string for type T. inline static std::string GetSignature() { return GetArrayDBusSignature(GetDBusSignature()); } inline static void Write(dbus::MessageWriter* writer, const std::vector& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, std::vector* value) { return PopValueFromReader(reader, value); } }; // Explicit specialization for unsupported type T. template struct DBusArrayType : public Unsupported {}; } // namespace details template struct DBusType> : public details::DBusArrayType::value, T, ALLOC> {}; // std::pair = D-Bus STRUCT with two elements. -------------------------------- namespace details { // Helper class to get a D-Bus signature of a list of types. // For example, TupleTraits::GetSignature() will // return "ibs". template struct TupleTraits; template struct TupleTraits { static std::string GetSignature() { return GetDBusSignature() + TupleTraits::GetSignature(); } }; template<> struct TupleTraits<> { static std::string GetSignature() { return std::string{}; } }; } // namespace details template inline std::string GetStructDBusSignature() { // Returns "(T...)", where "T..." is the signature strings for types T... return DBUS_STRUCT_BEGIN_CHAR_AS_STRING + details::TupleTraits::GetSignature() + DBUS_STRUCT_END_CHAR_AS_STRING; } template typename std::enable_if::value>::type AppendValueToWriter( dbus::MessageWriter* writer, const std::pair& value) { dbus::MessageWriter struct_writer(nullptr); writer->OpenStruct(&struct_writer); // Use DBusType::Write() instead of AppendValueToWriter() to delay // binding to AppendValueToWriter() to the point of instantiation of this // template. DBusType::Write(&struct_writer, value.first); DBusType::Write(&struct_writer, value.second); writer->CloseContainer(&struct_writer); } template typename std::enable_if::value, bool>::type PopValueFromReader(dbus::MessageReader* reader, std::pair* value) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader struct_reader(nullptr); if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) || !reader->PopStruct(&struct_reader)) return false; // Use DBusType::Read() instead of PopValueFromReader() to delay // binding to PopValueFromReader() to the point of instantiation of this // template. return DBusType::Read(&struct_reader, &value->first) && DBusType::Read(&struct_reader, &value->second); } namespace details { // DBusArrayType<> is a helper base class for DBusType> that provides // GetSignature/Write/Read methods for types that are supported by D-Bus // and not having those methods for types that are not supported by D-Bus. template struct DBusPairType { // Returns "(UV)", where "U" and "V" are the signature strings for types U, V. inline static std::string GetSignature() { return GetStructDBusSignature(); } inline static void Write(dbus::MessageWriter* writer, const std::pair& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, std::pair* value) { return PopValueFromReader(reader, value); } }; // Either U, or V, or both are not supported by D-Bus. template struct DBusPairType : public Unsupported {}; } // namespace details template struct DBusType> : public details::DBusPairType::value, U, V> {}; // std::tuple = D-Bus STRUCT with arbitrary number of members. ---------------- namespace details { // TupleIterator is a helper class to iterate over all the elements // of a tuple from index I to N. TupleIterator<>::Read and ::Write methods // are called for each element of the tuple and iteration continues until I == N // in which case the specialization for I==N below stops the recursion. template struct TupleIterator { // Tuple is just a convenience alias to a tuple containing elements of type T. using Tuple = std::tuple; // ValueType is the type of the element at index I. using ValueType = typename std::tuple_element::type; // Write the tuple element at index I to D-Bus message. static void Write(dbus::MessageWriter* writer, const Tuple& value) { // Use DBusType::Write() instead of AppendValueToWriter() to delay // binding to AppendValueToWriter() to the point of instantiation of this // template. DBusType::Write(writer, std::get(value)); TupleIterator::Write(writer, value); } // Read the tuple element at index I from D-Bus message. static bool Read(dbus::MessageReader* reader, Tuple* value) { // Use DBusType::Read() instead of PopValueFromReader() to delay // binding to PopValueFromReader() to the point of instantiation of this // template. return DBusType::Read(reader, &std::get(*value)) && TupleIterator::Read(reader, value); } }; // Specialization to end the iteration when the index reaches the last element. template struct TupleIterator { using Tuple = std::tuple; static void Write(dbus::MessageWriter* /* writer */, const Tuple& /* value */) {} static bool Read(dbus::MessageReader* /* reader */, Tuple* /* value */) { return true; } }; } // namespace details template typename std::enable_if::value>::type AppendValueToWriter( dbus::MessageWriter* writer, const std::tuple& value) { dbus::MessageWriter struct_writer(nullptr); writer->OpenStruct(&struct_writer); details::TupleIterator<0, sizeof...(T), T...>::Write(&struct_writer, value); writer->CloseContainer(&struct_writer); } template typename std::enable_if::value, bool>::type PopValueFromReader(dbus::MessageReader* reader, std::tuple* value) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader struct_reader(nullptr); if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) || !reader->PopStruct(&struct_reader)) return false; return details::TupleIterator<0, sizeof...(T), T...>::Read(&struct_reader, value); } namespace details { // DBusTupleType<> is a helper base class for DBusType> that // provides GetSignature/Write/Read methods for types that are supported by // D-Bus and not having those methods for types that are not supported by D-Bus. template struct DBusTupleType { // Returns "(T...)", where "T..." are the signature strings for types T... inline static std::string GetSignature() { return GetStructDBusSignature(); } inline static void Write(dbus::MessageWriter* writer, const std::tuple& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, std::tuple* value) { return PopValueFromReader(reader, value); } }; // Some/all of types T... are not supported by D-Bus. template struct DBusTupleType : public Unsupported {}; } // namespace details template struct DBusType> : public details::DBusTupleType::value, T...> {}; // std::map = D-Bus ARRAY of DICT_ENTRY. -------------------------------------- template typename std::enable_if::value>::type AppendValueToWriter(dbus::MessageWriter* writer, const std::map& value) { dbus::MessageWriter dict_writer(nullptr); writer->OpenArray(details::GetDBusDictEntryType(), &dict_writer); for (const auto& pair : value) { dbus::MessageWriter entry_writer(nullptr); dict_writer.OpenDictEntry(&entry_writer); // Use DBusType::Write() instead of AppendValueToWriter() to delay // binding to AppendValueToWriter() to the point of instantiation of this // template. DBusType::Write(&entry_writer, pair.first); DBusType::Write(&entry_writer, pair.second); dict_writer.CloseContainer(&entry_writer); } writer->CloseContainer(&dict_writer); } template typename std::enable_if::value, bool>::type PopValueFromReader(dbus::MessageReader* reader, std::map* value) { dbus::MessageReader variant_reader(nullptr); dbus::MessageReader array_reader(nullptr); if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) || !reader->PopArray(&array_reader)) return false; value->clear(); while (array_reader.HasMoreData()) { dbus::MessageReader dict_entry_reader(nullptr); if (!array_reader.PopDictEntry(&dict_entry_reader)) return false; KEY key; VALUE data; // Use DBusType::Read() instead of PopValueFromReader() to delay // binding to PopValueFromReader() to the point of instantiation of this // template. if (!DBusType::Read(&dict_entry_reader, &key) || !DBusType::Read(&dict_entry_reader, &data)) return false; value->emplace(std::move(key), std::move(data)); } return true; } namespace details { // DBusArrayType<> is a helper base class for DBusType> that provides // GetSignature/Write/Read methods for T types that are supported by D-Bus // and not having those methods for types that are not supported by D-Bus. template struct DBusMapType { // Returns "a{KV}", where "K" and "V" are the signature strings for types // KEY/VALUE. inline static std::string GetSignature() { return GetArrayDBusSignature(GetDBusDictEntryType()); } inline static void Write(dbus::MessageWriter* writer, const std::map& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, std::map* value) { return PopValueFromReader(reader, value); } }; // Types KEY, VALUE or both are not supported by D-Bus. template struct DBusMapType : public Unsupported {}; } // namespace details template struct DBusType> : public details::DBusMapType::value, KEY, VALUE, PRED, ALLOC> {}; // google::protobuf::MessageLite = D-Bus ARRAY of BYTE ------------------------ inline void AppendValueToWriter(dbus::MessageWriter* writer, const google::protobuf::MessageLite& value) { writer->AppendProtoAsArrayOfBytes(value); } inline bool PopValueFromReader(dbus::MessageReader* reader, google::protobuf::MessageLite* value) { return reader->PopArrayOfBytesAsProto(value); } // is_protobuf_t is a helper type trait to determine if type T derives from // google::protobuf::MessageLite. template using is_protobuf = std::is_base_of; // Specialize DBusType for classes that derive from protobuf::MessageLite. // Here we perform a partial specialization of DBusType only for types // that derive from google::protobuf::MessageLite. This is done by employing // the second template parameter in DBusType and this basically relies on C++ // SFINAE rules. "typename std::enable_if::value>::type" will // evaluate to "void" for classes T that descend from MessageLite and will be // an invalid construct for other types/classes which will automatically // remove this particular specialization from name resolution context. template struct DBusType::value>::type> { inline static std::string GetSignature() { return GetDBusSignature>(); } inline static void Write(dbus::MessageWriter* writer, const T& value) { AppendValueToWriter(writer, value); } inline static bool Read(dbus::MessageReader* reader, T* value) { return PopValueFromReader(reader, value); } }; //---------------------------------------------------------------------------- // AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const T& value) // Write the |value| of type T to D-Bus message as a VARIANT. // This overload is provided only if T is supported by D-Bus. template typename std::enable_if::value>::type AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const T& value) { std::string data_type = GetDBusSignature(); dbus::MessageWriter variant_writer(nullptr); writer->OpenVariant(data_type, &variant_writer); // Use DBusType::Write() instead of AppendValueToWriter() to delay // binding to AppendValueToWriter() to the point of instantiation of this // template. DBusType::Write(&variant_writer, value); writer->CloseContainer(&variant_writer); } // Special case: do not allow to write a Variant containing a Variant. // Just redirect to normal AppendValueToWriter(). inline void AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const brillo::Any& value) { return AppendValueToWriter(writer, value); } //---------------------------------------------------------------------------- // PopVariantValueFromReader(dbus::MessageWriter* writer, T* value) // Reads a Variant containing the |value| of type T from D-Bus message. // Note that the generic PopValueFromReader(...) can do this too. // This method is provided for two reasons: // 1. For API symmetry with AppendValueToWriter/AppendValueToWriterAsVariant. // 2. To be used when it is important to assert that the data was sent // specifically as a Variant. // This overload is provided only if T is supported by D-Bus. template typename std::enable_if::value, bool>::type PopVariantValueFromReader(dbus::MessageReader* reader, T* value) { dbus::MessageReader variant_reader(nullptr); if (!reader->PopVariant(&variant_reader)) return false; // Use DBusType::Read() instead of PopValueFromReader() to delay // binding to PopValueFromReader() to the point of instantiation of this // template. return DBusType::Read(&variant_reader, value); } // Special handling of request to read a Variant of Variant. inline bool PopVariantValueFromReader(dbus::MessageReader* reader, Any* value) { return PopValueFromReader(reader, value); } } // namespace dbus_utils } // namespace brillo #endif // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_