| // Copyright 2014 The ChromiumOS Authors | |
| // 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 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); | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <tuple> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/files/scoped_file.h> | |
| #include <base/logging.h> | |
| #include <brillo/brillo_export.h> | |
| #include <brillo/dbus/dbus_signature.h> | |
| #include <brillo/type_name_undecorate.h> | |
| #include <dbus/message.h> | |
| 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<T> for T not supported by D-Bus. This used to | |
| // implement IsTypeSupported<> below. | |
| struct Unsupported {}; | |
| // Generic definition of DBusType<T> 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 <typename T, typename = void> | |
| 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 <typename... Types> | |
| struct IsTypeSupported; | |
| // Both T and the Types... must be supported for the complete set to be | |
| // supported. | |
| template <typename T, typename... Types> | |
| struct IsTypeSupported<T, Types...> | |
| : public std::integral_constant<bool, | |
| IsTypeSupported<T>::value && | |
| IsTypeSupported<Types...>::value> {}; | |
| // For a single type T, check if DBusType<T> derives from Unsupported. | |
| // If it does, then the type is not supported by the D-Bus. | |
| template <typename T> | |
| struct IsTypeSupported<T> | |
| : public std::integral_constant< | |
| bool, | |
| !std::is_base_of<Unsupported, DBusType<T>>::value> {}; | |
| // Empty set is not supported. | |
| template <> | |
| struct IsTypeSupported<> : public std::false_type {}; | |
| //---------------------------------------------------------------------------- | |
| // AppendValueToWriter<T>(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<T>(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; | |
| 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. | |
| // TODO(b/289932268): To catch actual errors, unwrapping should be done | |
| // explicitly. Thus, this should be removed. Handling D-Bus variant should be | |
| // done in other place explicitly. | |
| BRILLO_EXPORT bool DescendIntoVariantIfPresent( | |
| ::dbus::MessageReader** reader_ref, | |
| ::dbus::MessageReader* variant_reader, | |
| bool for_any = false); | |
| } // namespace details | |
| //============================================================================= | |
| // Specializations/overloads for AppendValueToWriter, PopValueFromReader and | |
| // DBusType<T> 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<bool> { | |
| 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<uint8_t> { | |
| 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<int16_t> { | |
| 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<uint16_t> { | |
| 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<int32_t> { | |
| 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<uint32_t> { | |
| 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<int64_t> { | |
| 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<uint64_t> { | |
| 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<double> { | |
| 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<std::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<const char*> { | |
| inline static void Write(::dbus::MessageWriter* writer, const char* value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| }; | |
| // const char[] | |
| template <> | |
| struct DBusType<const char[]> { | |
| 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<::dbus::ObjectPath> { | |
| 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); | |
| } | |
| }; | |
| // base::ScopedFD ------------------------------------------------------------- | |
| BRILLO_EXPORT void AppendValueToWriter(::dbus::MessageWriter* writer, | |
| const base::ScopedFD& value); | |
| BRILLO_EXPORT bool PopValueFromReader(::dbus::MessageReader* reader, | |
| base::ScopedFD* value); | |
| template <> | |
| struct DBusType<base::ScopedFD> { | |
| inline static void Write(::dbus::MessageWriter* writer, | |
| const base::ScopedFD& value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| 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<brillo::Any> { | |
| 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 T, typename ALLOC> | |
| typename std::enable_if<IsTypeSupported<T>::value>::type AppendValueToWriter( | |
| ::dbus::MessageWriter* writer, const std::vector<T, ALLOC>& value) { | |
| ::dbus::MessageWriter array_writer(nullptr); | |
| writer->OpenArray(GetDBusSignature<T>(), &array_writer); | |
| for (const auto& element : value) { | |
| // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay | |
| // binding to AppendValueToWriter() to the point of instantiation of this | |
| // template. | |
| DBusType<T>::Write(&array_writer, element); | |
| } | |
| writer->CloseContainer(&array_writer); | |
| } | |
| template <typename T, typename ALLOC> | |
| typename std::enable_if<IsTypeSupported<T>::value, bool>::type | |
| PopValueFromReader(::dbus::MessageReader* reader, | |
| std::vector<T, ALLOC>* value) { | |
| ::dbus::MessageReader array_reader(nullptr); | |
| if (!reader->PopArray(&array_reader)) { | |
| return false; | |
| } | |
| value->clear(); | |
| while (array_reader.HasMoreData()) { | |
| T data; | |
| // Use DBusType<T>::Read() instead of PopValueFromReader() to delay | |
| // binding to PopValueFromReader() to the point of instantiation of this | |
| // template. | |
| if (!DBusType<T>::Read(&array_reader, &data)) | |
| return false; | |
| value->push_back(std::move(data)); | |
| } | |
| return true; | |
| } | |
| namespace details { | |
| // DBusArrayType<> is a helper base class for DBusType<vector<T>> that provides | |
| // 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 <bool inner_type_supported, typename T, typename ALLOC> | |
| struct DBusArrayType { | |
| inline static void Write(::dbus::MessageWriter* writer, | |
| const std::vector<T, ALLOC>& value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| inline static bool Read(::dbus::MessageReader* reader, | |
| std::vector<T, ALLOC>* value) { | |
| return PopValueFromReader(reader, value); | |
| } | |
| }; | |
| // Explicit specialization for unsupported type T. | |
| template <typename T, typename ALLOC> | |
| struct DBusArrayType<false, T, ALLOC> : public Unsupported {}; | |
| } // namespace details | |
| template <typename T, typename ALLOC> | |
| struct DBusType<std::vector<T, ALLOC>> | |
| : public details::DBusArrayType<IsTypeSupported<T>::value, T, ALLOC> {}; | |
| // std::pair = D-Bus STRUCT with two elements. -------------------------------- | |
| template <typename U, typename V> | |
| typename std::enable_if<IsTypeSupported<U, V>::value>::type AppendValueToWriter( | |
| ::dbus::MessageWriter* writer, const std::pair<U, V>& value) { | |
| ::dbus::MessageWriter struct_writer(nullptr); | |
| writer->OpenStruct(&struct_writer); | |
| // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay | |
| // binding to AppendValueToWriter() to the point of instantiation of this | |
| // template. | |
| DBusType<U>::Write(&struct_writer, value.first); | |
| DBusType<V>::Write(&struct_writer, value.second); | |
| writer->CloseContainer(&struct_writer); | |
| } | |
| template <typename U, typename V> | |
| typename std::enable_if<IsTypeSupported<U, V>::value, bool>::type | |
| PopValueFromReader(::dbus::MessageReader* reader, std::pair<U, V>* value) { | |
| ::dbus::MessageReader struct_reader(nullptr); | |
| if (!reader->PopStruct(&struct_reader)) { | |
| return false; | |
| } | |
| // Use DBusType<T>::Read() instead of PopValueFromReader() to delay | |
| // binding to PopValueFromReader() to the point of instantiation of this | |
| // template. | |
| return DBusType<U>::Read(&struct_reader, &value->first) && | |
| DBusType<V>::Read(&struct_reader, &value->second); | |
| } | |
| namespace details { | |
| // DBusArrayType<> is a helper base class for DBusType<pair<U, V>> that provides | |
| // 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 <bool inner_type_supported, typename U, typename V> | |
| struct DBusPairType { | |
| inline static void Write(::dbus::MessageWriter* writer, | |
| const std::pair<U, V>& value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| inline static bool Read(::dbus::MessageReader* reader, | |
| std::pair<U, V>* value) { | |
| return PopValueFromReader(reader, value); | |
| } | |
| }; | |
| // Either U, or V, or both are not supported by D-Bus. | |
| template <typename U, typename V> | |
| struct DBusPairType<false, U, V> : public Unsupported {}; | |
| } // namespace details | |
| template <typename U, typename V> | |
| struct DBusType<std::pair<U, V>> | |
| : public details::DBusPairType<IsTypeSupported<U, V>::value, U, V> {}; | |
| // std::tuple = D-Bus STRUCT with arbitrary number of members. ---------------- | |
| namespace details { | |
| // TupleIterator<I, N, T...> is a helper class to iterate over all the elements | |
| // of a tuple<T...> 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 <size_t I, size_t N, typename... T> | |
| struct TupleIterator { | |
| // Tuple is just a convenience alias to a tuple containing elements of type T. | |
| using Tuple = std::tuple<T...>; | |
| // ValueType is the type of the element at index I. | |
| using ValueType = typename std::tuple_element<I, Tuple>::type; | |
| // Write the tuple element at index I to D-Bus message. | |
| static void Write(::dbus::MessageWriter* writer, const Tuple& value) { | |
| // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay | |
| // binding to AppendValueToWriter() to the point of instantiation of this | |
| // template. | |
| DBusType<ValueType>::Write(writer, std::get<I>(value)); | |
| TupleIterator<I + 1, N, T...>::Write(writer, value); | |
| } | |
| // Read the tuple element at index I from D-Bus message. | |
| static bool Read(::dbus::MessageReader* reader, Tuple* value) { | |
| // Use DBusType<T>::Read() instead of PopValueFromReader() to delay | |
| // binding to PopValueFromReader() to the point of instantiation of this | |
| // template. | |
| return DBusType<ValueType>::Read(reader, &std::get<I>(*value)) && | |
| TupleIterator<I + 1, N, T...>::Read(reader, value); | |
| } | |
| }; | |
| // Specialization to end the iteration when the index reaches the last element. | |
| template <size_t N, typename... T> | |
| struct TupleIterator<N, N, T...> { | |
| using Tuple = std::tuple<T...>; | |
| static void Write(::dbus::MessageWriter* /* writer */, | |
| const Tuple& /* value */) {} | |
| static bool Read(::dbus::MessageReader* /* reader */, Tuple* /* value */) { | |
| return true; | |
| } | |
| }; | |
| } // namespace details | |
| template <typename... T> | |
| typename std::enable_if<IsTypeSupported<T...>::value>::type AppendValueToWriter( | |
| ::dbus::MessageWriter* writer, const std::tuple<T...>& 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... T> | |
| typename std::enable_if<IsTypeSupported<T...>::value, bool>::type | |
| PopValueFromReader(::dbus::MessageReader* reader, std::tuple<T...>* value) { | |
| ::dbus::MessageReader struct_reader(nullptr); | |
| if (!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<tuple<T...>> that | |
| // provides 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 <bool inner_type_supported, typename... T> | |
| struct DBusTupleType { | |
| inline static void Write(::dbus::MessageWriter* writer, | |
| const std::tuple<T...>& value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| inline static bool Read(::dbus::MessageReader* reader, | |
| std::tuple<T...>* value) { | |
| return PopValueFromReader(reader, value); | |
| } | |
| }; | |
| // Some/all of types T... are not supported by D-Bus. | |
| template <typename... T> | |
| struct DBusTupleType<false, T...> : public Unsupported {}; | |
| } // namespace details | |
| template <typename... T> | |
| struct DBusType<std::tuple<T...>> | |
| : public details::DBusTupleType<IsTypeSupported<T...>::value, T...> {}; | |
| // std::map = D-Bus ARRAY of DICT_ENTRY. -------------------------------------- | |
| template <typename KEY, typename VALUE, typename PRED, typename ALLOC> | |
| typename std::enable_if<IsTypeSupported<KEY, VALUE>::value>::type | |
| AppendValueToWriter(::dbus::MessageWriter* writer, | |
| const std::map<KEY, VALUE, PRED, ALLOC>& value) { | |
| ::dbus::MessageWriter dict_writer(nullptr); | |
| writer->OpenArray(internal::StrJoin("{", DBusSignature<KEY>::kValue, | |
| DBusSignature<VALUE>::kValue, "}") | |
| .data(), | |
| &dict_writer); | |
| for (const auto& pair : value) { | |
| ::dbus::MessageWriter entry_writer(nullptr); | |
| dict_writer.OpenDictEntry(&entry_writer); | |
| // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay | |
| // binding to AppendValueToWriter() to the point of instantiation of this | |
| // template. | |
| DBusType<KEY>::Write(&entry_writer, pair.first); | |
| DBusType<VALUE>::Write(&entry_writer, pair.second); | |
| dict_writer.CloseContainer(&entry_writer); | |
| } | |
| writer->CloseContainer(&dict_writer); | |
| } | |
| template <typename KEY, typename VALUE, typename PRED, typename ALLOC> | |
| typename std::enable_if<IsTypeSupported<KEY, VALUE>::value, bool>::type | |
| PopValueFromReader(::dbus::MessageReader* reader, | |
| std::map<KEY, VALUE, PRED, ALLOC>* value) { | |
| ::dbus::MessageReader array_reader(nullptr); | |
| if (!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<T>::Read() instead of PopValueFromReader() to delay | |
| // binding to PopValueFromReader() to the point of instantiation of this | |
| // template. | |
| if (!DBusType<KEY>::Read(&dict_entry_reader, &key) || | |
| !DBusType<VALUE>::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<map<K, V>> that provides | |
| // 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 <bool inner_types_supported, | |
| typename KEY, | |
| typename VALUE, | |
| typename PRED, | |
| typename ALLOC> | |
| struct DBusMapType { | |
| inline static void Write(::dbus::MessageWriter* writer, | |
| const std::map<KEY, VALUE, PRED, ALLOC>& value) { | |
| AppendValueToWriter(writer, value); | |
| } | |
| inline static bool Read(::dbus::MessageReader* reader, | |
| std::map<KEY, VALUE, PRED, ALLOC>* value) { | |
| return PopValueFromReader(reader, value); | |
| } | |
| }; | |
| // Types KEY, VALUE or both are not supported by D-Bus. | |
| template <typename KEY, typename VALUE, typename PRED, typename ALLOC> | |
| struct DBusMapType<false, KEY, VALUE, PRED, ALLOC> : public Unsupported {}; | |
| } // namespace details | |
| template <typename KEY, typename VALUE, typename PRED, typename ALLOC> | |
| struct DBusType<std::map<KEY, VALUE, PRED, ALLOC>> | |
| : public details::DBusMapType<IsTypeSupported<KEY, VALUE>::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<T> is a helper type trait to determine if type T derives from | |
| // google::protobuf::MessageLite. | |
| template <typename T> | |
| using is_protobuf = std::is_base_of<google::protobuf::MessageLite, T>; | |
| // Specialize DBusType<T> for classes that derive from protobuf::MessageLite. | |
| // Here we perform a partial specialization of DBusType<T> 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<is_protobuf<T>::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 <typename T> | |
| struct DBusType<T, typename std::enable_if<is_protobuf<T>::value>::type> { | |
| 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<T>(::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 T> | |
| typename std::enable_if<IsTypeSupported<T>::value>::type | |
| AppendValueToWriterAsVariant(::dbus::MessageWriter* writer, const T& value) { | |
| ::dbus::MessageWriter variant_writer(nullptr); | |
| writer->OpenVariant(GetDBusSignature<T>(), &variant_writer); | |
| // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay | |
| // binding to AppendValueToWriter() to the point of instantiation of this | |
| // template. | |
| DBusType<T>::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<T>(::dbus::MessageWriter* writer, T* value) | |
| // Reads a Variant containing the |value| of type T from D-Bus message. | |
| // Note that the generic PopValueFromReader<T>(...) 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 T> | |
| typename std::enable_if<IsTypeSupported<T>::value, bool>::type | |
| PopVariantValueFromReader(::dbus::MessageReader* reader, T* value) { | |
| ::dbus::MessageReader variant_reader(nullptr); | |
| if (!reader->PopVariant(&variant_reader)) | |
| return false; | |
| // Use DBusType<T>::Read() instead of PopValueFromReader() to delay | |
| // binding to PopValueFromReader() to the point of instantiation of this | |
| // template. | |
| return DBusType<T>::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); | |
| } | |
| // Returns the type to store the D-Bus argument value. | |
| // In-arg type is const T&, while out-arg type is T*. | |
| // They will be converted into T. | |
| template <typename T> | |
| using StorageType = std::decay_t<std::remove_pointer_t<T>>; | |
| // Reads the D-Bus arguments from |reader| to each |args| in order. | |
| // Returns true on success, including there's no arguments remaining. | |
| template <typename... Args> | |
| bool ReadDBusArgs(dbus::MessageReader* reader, Args*... args) { | |
| return (DBusType<std::decay_t<Args>>::Read(reader, args) && ...) && | |
| !reader->HasMoreData(); | |
| } | |
| // Taking a tuple of either 1) references to arguments, or 2) storages | |
| // of arguments, then read the D-Bus arguments to there. | |
| template <typename Tuple> | |
| bool ApplyReadDBusArgs(dbus::MessageReader* reader, Tuple&& tuple) { | |
| return std::apply( | |
| [reader](auto&&... in_args) { return ReadDBusArgs(reader, &in_args...); }, | |
| std::forward<Tuple>(tuple)); | |
| } | |
| // Writes the D-Bus arguments to |writer| in order. | |
| template <typename... Args> | |
| void WriteDBusArgs(dbus::MessageWriter* writer, const Args&... args) { | |
| (DBusType<std::decay_t<Args>>::Write(writer, args), ...); | |
| } | |
| // Currently, D-Bus arg reading function automatically unwraps variant, | |
| // so even if the type is different from the spec, that may be read | |
| // unexpectedly. That will be removed, and this is the flag for its | |
| // safer migration. See also b/289932268. | |
| enum class AutoVariantUnwrapState { | |
| // Enabled the automatic variant unwrapping, i.e., the original state. | |
| kEnabled, | |
| // Still automatically unwrapped, but crash dump (without actual crash) will | |
| // be reported when it happens. So, we can identify the cases in the world. | |
| kDumpWithoutCrash, | |
| // Disabled the automatic variant, which is the eventual state. | |
| kDisabled, | |
| }; | |
| BRILLO_EXPORT void SetAutoVariantUnwrapState(AutoVariantUnwrapState state); | |
| BRILLO_EXPORT AutoVariantUnwrapState GetAutoVariantUnwrapState(); | |
| } // namespace dbus_utils | |
| } // namespace brillo | |
| #endif // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_ |