libchromeos: Fix DBus data serialization to work with custom types
The previous implementation suffered from C++ binding rules for
non-dependent names in templates. Template functions such as
AppendValueToWriter and PopValueFromReader for template types such
as std::vector<T> and std::map<K,V> are limited to the types defined
in libchromeos because the implementations calling the inner overloads
for types such as T would only select functions defined before the
overloads for vector and map are defined.
This forced the custom implementations of user-provided types to
be included before chromeos/dbus/data_serialization.h and having
the code depend on the order of includes is a very dangerous thing.
To make the problem worse, generic AppendValueToWriter<T> is always
a default fall-back for any unknown types and it simply fails at run-time
which makes it very difficult to detect unintended problems.
The reason why the generic AppendValueToWriter<T>() was provided is to
allow chromeos::Any to contain any C++ type but still be able to use
with D-Bus subset of types to implement the D-Bus's VARIANT type.
This change addresses the above problems as follows:
- The template functionality depending on custom overloads of
AppendValueToWriter and PopValueFromReader now call them indirectly
through DBusType<T>::Write and DBusType<T>::Read helpers that delay
binding to the correct overload of Append... and Pop... until the
template instantiation.
- Marked the generic AppendValueToWriter<T> and PopValueFromReader<T>
as "deleted" functions so the compilation would break as soon as
these functions are called with an unsupported types.
- Provided IsTypeSupported<T...> type trait to help specialize the
implementation for only supported D-Bus types. This allows, for
example, specialization of vector<T> to work for supported types
T and fail immediately for T that are not supported by D-Bus.
- Used IsTypeSupported<T> in chromeos::Any to disable calls to
AppendValueToWriter at compile time for unsupported types.
- Made AppendValueToWriter() a void function. Now it doesn't fail.
The internal implementation inside chromeos::Any uses CHECK() to
ensure the contained class which will abort as soon as Any,
containing datat of an unsupported type, is being written to
D-Bus message buffer.
BUG=chromium:431744
TEST=FEATURES=test emerge-link libchromeos attestation buffet peerd
Change-Id: I13431f74797b8b92082f172a067ea1515a7aa73e
Reviewed-on: https://chromium-review.googlesource.com/228731
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos/any.cc b/chromeos/any.cc
index 2f54871..4cedff6 100644
--- a/chromeos/any.cc
+++ b/chromeos/any.cc
@@ -72,10 +72,9 @@
return data_buffer_.GetDataPtr()->GetAsInteger();
}
-bool Any::AppendToDBusMessageWriter(dbus::MessageWriter* writer) const {
- if (IsEmpty())
- return false;
- return data_buffer_.GetDataPtr()->AppendToDBusMessage(writer);
+void Any::AppendToDBusMessageWriter(dbus::MessageWriter* writer) const {
+ CHECK(!IsEmpty()) << "Must not be called on an empty Any";
+ data_buffer_.GetDataPtr()->AppendToDBusMessage(writer);
}
} // namespace chromeos
diff --git a/chromeos/any.h b/chromeos/any.h
index 3f0197b..bda7e60 100644
--- a/chromeos/any.h
+++ b/chromeos/any.h
@@ -174,7 +174,7 @@
// (an appropriate specialization of AppendValueToWriter<T>() is available).
// Returns false if the Any is empty or if there is no serialization method
// defined for the contained data.
- bool AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
+ void AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
private:
// The data buffer for contained object.
diff --git a/chromeos/any_internal_impl.h b/chromeos/any_internal_impl.h
index 828905c..13aef03 100644
--- a/chromeos/any_internal_impl.h
+++ b/chromeos/any_internal_impl.h
@@ -148,7 +148,7 @@
// Gets the contained integral value as an integer.
virtual intmax_t GetAsInteger() const = 0;
// Writes the contained value to the D-Bus message buffer.
- virtual bool AppendToDBusMessage(dbus::MessageWriter* writer) const = 0;
+ virtual void AppendToDBusMessage(dbus::MessageWriter* writer) const = 0;
// Compares if the two data containers have objects of the same value.
virtual bool CompareEqual(const Data* other_data) const = 0;
};
@@ -174,8 +174,21 @@
<< "' to integer";
return int_val;
}
- bool AppendToDBusMessage(dbus::MessageWriter* writer) const override {
- return chromeos::dbus_utils::AppendValueToWriterAsVariant(writer, value_);
+
+ template<typename U>
+ static typename std::enable_if<dbus_utils::IsTypeSupported<U>::value>::type
+ AppendValueHelper(dbus::MessageWriter* writer, const U& value) {
+ chromeos::dbus_utils::AppendValueToWriterAsVariant(writer, value);
+ }
+ template<typename U>
+ static typename std::enable_if<!dbus_utils::IsTypeSupported<U>::value>::type
+ AppendValueHelper(dbus::MessageWriter* writer, const U& value) {
+ LOG(FATAL) << "Type '" << GetUndecoratedTypeName<U>()
+ << "' is not supported by D-Bus";
+ }
+
+ void AppendToDBusMessage(dbus::MessageWriter* writer) const override {
+ return AppendValueHelper(writer, value_);
}
bool CompareEqual(const Data* other_data) const override {
diff --git a/chromeos/dbus/data_serialization.cc b/chromeos/dbus/data_serialization.cc
index 30c09df..b389ce0 100644
--- a/chromeos/dbus/data_serialization.cc
+++ b/chromeos/dbus/data_serialization.cc
@@ -10,76 +10,64 @@
namespace chromeos {
namespace dbus_utils {
-bool AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
writer->AppendBool(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
writer->AppendByte(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
writer->AppendInt16(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
writer->AppendUint16(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
writer->AppendInt32(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
writer->AppendUint32(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
writer->AppendInt64(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
writer->AppendUint64(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, double value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, double value) {
writer->AppendDouble(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
const std::string& value) {
writer->AppendString(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
- return AppendValueToWriter(writer, std::string(value));
+void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
+ AppendValueToWriter(writer, std::string(value));
}
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
const dbus::ObjectPath& value) {
writer->AppendObjectPath(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
const dbus::FileDescriptor& value) {
writer->AppendFileDescriptor(value);
- return true;
}
-bool AppendValueToWriter(dbus::MessageWriter* writer,
+void AppendValueToWriter(dbus::MessageWriter* writer,
const chromeos::Any& value) {
- return value.AppendToDBusMessageWriter(writer);
+ value.AppendToDBusMessageWriter(writer);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chromeos/dbus/data_serialization.h b/chromeos/dbus/data_serialization.h
index 9a96ecd..3a31adf 100644
--- a/chromeos/dbus/data_serialization.h
+++ b/chromeos/dbus/data_serialization.h
@@ -10,8 +10,8 @@
// - Methods to get the D-Bus signature for a given C++ type:
// std::string GetDBusSignature<T>();
// - Methods to write arbitrary C++ data to D-Bus MessageWriter:
-// bool AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
-// bool AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
+// 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);
@@ -40,9 +40,18 @@
//
// (*) - Currently, only 2 element STRUCTs are supported as std::pair. In the
// future we can add a generic std::tuple<...> support for arbitrary number
-// of struct members. Implementations could also provide specializations for
-// custom C++ structures for AppendValueToWriter/PopValueFromReader.
-// See an example in DBusUtils.CustomStruct unit test in dbus_utils_unittest.cc.
+// of struct members.
+//
+// Additional overloads/specialization can be provided for custom types.
+// In order to do that, provide overloads of AppendValueToWriter() and
+// PopValueFromReader() functions in chromeos::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
+// chromeos/dbus/data_serialization_unittest.cc.
#include <map>
#include <memory>
@@ -69,29 +78,94 @@
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.
+template<typename T>
+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.
+// The default implementation is marked as "deleted". This method must be
+// overloaded for specific types to allow serialization over D-Bus.
+// If this function causes compile-time error, this means that either
+// the type T is not supported by D-Bus or you haven't provided an overload
+// for custom types you want to serialize over D-Bus. See the comment at the
+// top of this file for explanation of how to add custom data serialization
+// code.
+template<typename T>
+void AppendValueToWriter(dbus::MessageWriter* writer, const T& value) = delete;
+
+//----------------------------------------------------------------------------
+// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
+// Reads the |value| of type T from D-Bus message. These methods can read both
+// actual data of type T and data of type T sent over D-Bus as a Variant.
+// This allows it, for example, to read a generic dictionary ("a{sv}") as
+// a specific map type (e.g. "a{ss}", if a map of string-to-string is expected).
+// The default implementation is marked as "deleted". This method must be
+// overloaded for specific types to allow serialization over D-Bus.
+// If this function causes compile-time error, this means that either
+// the type T is not supported by D-Bus or you haven't provided an overload
+// for custom types you want to serialize over D-Bus. See the comment at the
+// top of this file for explanation of how to add custom data serialization
+// code.
+template<typename T>
+void PopValueFromReader(dbus::MessageReader* reader, T* value) = delete;
+
//----------------------------------------------------------------------------
// Get D-Bus data signature from C++ data types.
// Specializations of a generic GetDBusSignature<T>() provide signature strings
-// for native C++ types.
-
-// It is not possible to provide partial specialization for template functions,
-// so we are using a helper template struct with a static member getter,
-// DBusSignature<T>::get(), to work around this problem. So, we do partial
-// specialization of DBusSignature<T> instead, and have GetDBusSignature<T>()
-// just call DBusSignature<T>::get().
-
-template<typename T> std::string GetDBusSignature(); // Forward declaration.
-
-// Generic template getter that fails for all types unless an explicit
-// specialization is provided for.
+// for native C++ types. This function is available only for type supported
+// by D-Bus.
template<typename T>
-struct DBusSignature {
- inline static std::string get() {
- LOG(ERROR) << "Type '" << GetUndecoratedTypeName<T>()
- << "' is not supported by D-Bus";
- return std::string();
- }
-};
+inline typename std::enable_if<IsTypeSupported<T>::value, std::string>::type
+GetDBusSignature() {
+ return DBusType<T>::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|.
@@ -110,297 +184,309 @@
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
}
-// Specializations of DBusSignature<T> for basic D-Bus types.
-template<> struct DBusSignature<bool> {
- inline static std::string get() { return DBUS_TYPE_BOOLEAN_AS_STRING; }
-};
-template<> struct DBusSignature<uint8_t> {
- inline static std::string get() { return DBUS_TYPE_BYTE_AS_STRING; }
-};
-template<> struct DBusSignature<int16_t> {
- inline static std::string get() { return DBUS_TYPE_INT16_AS_STRING; }
-};
-template<> struct DBusSignature<uint16_t> {
- inline static std::string get() { return DBUS_TYPE_UINT16_AS_STRING; }
-};
-template<> struct DBusSignature<int32_t> {
- inline static std::string get() { return DBUS_TYPE_INT32_AS_STRING; }
-};
-template<> struct DBusSignature<uint32_t> {
- inline static std::string get() { return DBUS_TYPE_UINT32_AS_STRING; }
-};
-template<> struct DBusSignature<int64_t> {
- inline static std::string get() { return DBUS_TYPE_INT64_AS_STRING; }
-};
-template<> struct DBusSignature<uint64_t> {
- inline static std::string get() { return DBUS_TYPE_UINT64_AS_STRING; }
-};
-template<> struct DBusSignature<double> {
- inline static std::string get() { return DBUS_TYPE_DOUBLE_AS_STRING; }
-};
-template<> struct DBusSignature<const char*> {
- inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<const char[]> {
- inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<std::string> {
- inline static std::string get() { return DBUS_TYPE_STRING_AS_STRING; }
-};
-template<> struct DBusSignature<dbus::ObjectPath> {
- inline static std::string get() { return DBUS_TYPE_OBJECT_PATH_AS_STRING; }
-};
-template<> struct DBusSignature<dbus::FileDescriptor> {
- inline static std::string get() { return DBUS_TYPE_UNIX_FD_AS_STRING; }
-};
-template<> struct DBusSignature<chromeos::Any> {
- inline static std::string get() { return DBUS_TYPE_VARIANT_AS_STRING; }
-};
-
-// Specializations of DBusSignature<T> for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-struct DBusSignature<std::vector<T>> {
- // Returns "aT", where "T" is the signature string for type T.
- inline static std::string get() {
- return GetArrayDBusSignature(GetDBusSignature<T>());
- }
-};
-
-// std::pair = D-Bus STRUCT with two elements.
-template<typename U, typename V>
-struct DBusSignature<std::pair<U, V>> {
- // Returns "(UV)", where "U" and "V" are the signature strings for types U/V.
- inline static std::string get() {
- return DBUS_STRUCT_BEGIN_CHAR_AS_STRING + GetDBusSignature<U>() +
- GetDBusSignature<V>() + DBUS_STRUCT_END_CHAR_AS_STRING;
- }
-};
-
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-struct DBusSignature<std::map<KEY, VALUE>> {
- // Returns "a{KV}", where "K" and "V" are the signature strings for types
- // KEY/VALUE.
- inline static std::string get() {
- return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
- }
-};
-
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
-template<> struct DBusSignature<google::protobuf::MessageLite> {
- inline static std::string get() {
- return DBusSignature<std::vector<uint8_t>>::get();
- }
-};
-
-// The main worker function that returns a signature string for given type T.
-// For example, GetDBusSignature<std::map<int, bool>>() would return "a{ib}".
-template<typename T>
-inline std::string GetDBusSignature() { return DBusSignature<T>::get(); }
-
-//----------------------------------------------------------------------------
-// AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
-// Write the |value| of type T to D-Bus message.
-
-// Generic template method that fails for all types unless specifically
-// specialized for that type.
-template<typename T>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer, const T& value) {
- LOG(ERROR) << "Serialization of type '"
- << GetUndecoratedTypeName<T>() << "' not supported";
- return false;
-}
-
-// Numerous overloads for various native data types are provided below.
-
-// Basic types.
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- bool value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- uint8_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- int16_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- uint16_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- int32_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- uint32_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- int64_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- uint64_t value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- double value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- const std::string& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- const char* value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- const dbus::ObjectPath& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- const dbus::FileDescriptor& value);
-CHROMEOS_EXPORT bool AppendValueToWriter(dbus::MessageWriter* writer,
- const chromeos::Any& value);
-
-// Overloads of AppendValueToWriter for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
- const std::vector<T>& value) {
- std::string data_type = GetDBusSignature<T>();
- if (data_type.empty())
- return false;
- dbus::MessageWriter array_writer(nullptr);
- writer->OpenArray(data_type, &array_writer);
- bool success = true;
- for (const auto& element : value) {
- if (!AppendValueToWriter(&array_writer, element)) {
- success = false;
- break;
- }
- }
- writer->CloseContainer(&array_writer);
- return success;
-}
-
-// std::pair = D-Bus STRUCT with two elements.
-template<typename U, typename V>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
- const std::pair<U, V>& value) {
- dbus::MessageWriter struct_writer(nullptr);
- writer->OpenStruct(&struct_writer);
- bool success = AppendValueToWriter(&struct_writer, value.first) &&
- AppendValueToWriter(&struct_writer, value.second);
- writer->CloseContainer(&struct_writer);
- return success;
-}
-
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
- const std::map<KEY, VALUE>& value) {
- dbus::MessageWriter dict_writer(nullptr);
- writer->OpenArray(GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
- bool success = true;
- for (const auto& pair : value) {
- dbus::MessageWriter entry_writer(nullptr);
- dict_writer.OpenDictEntry(&entry_writer);
- success = AppendValueToWriter(&entry_writer, pair.first) &&
- AppendValueToWriter(&entry_writer, pair.second);
- dict_writer.CloseContainer(&entry_writer);
- if (!success)
- break;
- }
- writer->CloseContainer(&dict_writer);
- return success;
-}
-
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
-inline bool AppendValueToWriter(dbus::MessageWriter* writer,
- const google::protobuf::MessageLite& value) {
- writer->AppendProtoAsArrayOfBytes(value);
- return true;
-}
-
-//----------------------------------------------------------------------------
-// AppendValueToWriterAsVariant<T>(dbus::MessageWriter* writer, const T& value)
-// Write the |value| of type T to D-Bus message as a VARIANT
-template<typename T>
-inline bool AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
- const T& value) {
- std::string data_type = GetDBusSignature<T>();
- if (data_type.empty())
- return false;
- dbus::MessageWriter variant_writer(nullptr);
- writer->OpenVariant(data_type, &variant_writer);
- bool success = AppendValueToWriter(&variant_writer, value);
- writer->CloseContainer(&variant_writer);
- return success;
-}
-
-// Special case: do not allow to write a Variant containing a Variant.
-// Just redirect to normal AppendValueToWriter().
-inline bool AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
- const chromeos::Any& value) {
- return AppendValueToWriter(writer, value);
-}
-
-//----------------------------------------------------------------------------
-// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
-// Reads the |value| of type T from D-Bus message. These methods can read both
-// actual data of type T and data of type T sent over D-Bus as a Variant.
-// This allows it, for example, to read a generic dictionary ("a{sv}") as
-// a specific map type (e.g. "a{ss}", if a map of string-to-string is expected).
-
-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;
-}
} // namespace details
-// Generic template method that fails for all types unless specifically
-// specialized for that type.
-template<typename T>
-inline bool PopValueFromReader(dbus::MessageReader* reader, T* value) {
- LOG(ERROR) << "De-serialization of type '"
- << GetUndecoratedTypeName<T>() << "' not supported";
- return false;
+//=============================================================================
+// Specializations/overloads for AppendValueToWriter, PopValueFromReader and
+// DBusType<T> for various C++ types that can be serialized over D-Bus.
+
+// bool -----------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, bool value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, bool* value);
+
+template<>
+struct DBusType<bool> {
+ 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 --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, uint8_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, uint8_t* value);
+
+template<>
+struct DBusType<uint8_t> {
+ 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 --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, int16_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, int16_t* value);
+
+template<>
+struct DBusType<int16_t> {
+ 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 -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, uint16_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, uint16_t* value);
+
+template<>
+struct DBusType<uint16_t> {
+ 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 --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, int32_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, int32_t* value);
+
+template<>
+struct DBusType<int32_t> {
+ 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 -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, uint32_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, uint32_t* value);
+
+template<>
+struct DBusType<uint32_t> {
+ 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 --------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, int64_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, int64_t* value);
+
+template<>
+struct DBusType<int64_t> {
+ 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 -------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, uint64_t value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, uint64_t* value);
+
+template<>
+struct DBusType<uint64_t> {
+ 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 ---------------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, double value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, double* value);
+
+template<>
+struct DBusType<double> {
+ 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 ----------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, const std::string& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, std::string* value);
+
+template<>
+struct DBusType<std::string> {
+ 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*
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, const char* value);
+
+template<>
+struct DBusType<const char*> {
+ 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<const char[]> {
+ 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 -----------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, const dbus::ObjectPath& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, dbus::ObjectPath* value);
+
+template<>
+struct DBusType<dbus::ObjectPath> {
+ 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);
+ }
+};
+
+// dbus::FileDescriptor -------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(
+ dbus::MessageWriter* writer, const dbus::FileDescriptor& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, dbus::FileDescriptor* value);
+
+template<>
+struct DBusType<dbus::FileDescriptor> {
+ inline static std::string GetSignature() {
+ return DBUS_TYPE_UNIX_FD_AS_STRING;
+ }
+ inline static void Write(dbus::MessageWriter* writer,
+ const dbus::FileDescriptor& value) {
+ AppendValueToWriter(writer, value);
+ }
+ inline static bool Read(dbus::MessageReader* reader,
+ dbus::FileDescriptor* value) {
+ return PopValueFromReader(reader, value);
+ }
+};
+
+// chromeos::Any --------------------------------------------------------------
+CHROMEOS_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+ const chromeos::Any& value);
+CHROMEOS_EXPORT bool PopValueFromReader(
+ dbus::MessageReader* reader, chromeos::Any* value);
+
+template<>
+struct DBusType<chromeos::Any> {
+ inline static std::string GetSignature() {
+ return DBUS_TYPE_VARIANT_AS_STRING;
+ }
+ inline static void Write(dbus::MessageWriter* writer,
+ const chromeos::Any& value) {
+ AppendValueToWriter(writer, value);
+ }
+ inline static bool Read(dbus::MessageReader* reader, chromeos::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);
}
-// Numerous overloads for various native data types are provided below.
-
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- bool* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- uint8_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- int16_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- uint16_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- int32_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- uint32_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- int64_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- uint64_t* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- double* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- std::string* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- dbus::ObjectPath* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- dbus::FileDescriptor* value);
-CHROMEOS_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
- chromeos::Any* value);
-
-// Overloads of PopValueFromReader for some compound data types such
-// as ARRAYs, STRUCTs, DICTs.
-
-// std::vector = D-Bus ARRAY.
-template<typename T>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
- std::vector<T>* value) {
+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 variant_reader(nullptr);
dbus::MessageReader array_reader(nullptr);
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
@@ -409,30 +495,164 @@
value->clear();
while (array_reader.HasMoreData()) {
T data;
- if (!PopValueFromReader(&array_reader, &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;
}
-// std::pair = D-Bus STRUCT with two elements.
+namespace details {
+// DBusArrayType<> is a helper base class for DBusType<vector<T>> 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<bool inner_type_supported, typename T, typename ALLOC>
+struct DBusArrayType {
+ // Returns "aT", where "T" is the signature string for type T.
+ inline static std::string GetSignature() {
+ return GetArrayDBusSignature(GetDBusSignature<T>());
+ }
+ 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. --------------------------------
+namespace details {
+
+// Helper class to get a D-Bus signature of a list of types.
+// For example, TupleTraits<int32_t, bool, std::string>::GetSignature() will
+// return "ibs".
+template<typename... Types>
+struct TupleTraits;
+
+template<typename FirstType, typename... RestOfTypes>
+struct TupleTraits<FirstType, RestOfTypes...> {
+ static std::string GetSignature() {
+ return GetDBusSignature<FirstType>() +
+ TupleTraits<RestOfTypes...>::GetSignature();
+ }
+};
+
+template<>
+struct TupleTraits<> {
+ static std::string GetSignature() {
+ return std::string{};
+ }
+};
+
+} // namespace details
+
+template<typename... Types>
+inline std::string GetStructDBusSignature() {
+ // Returns "(T...)", where "T..." is the signature strings for types T...
+ return DBUS_STRUCT_BEGIN_CHAR_AS_STRING +
+ details::TupleTraits<Types...>::GetSignature() +
+ DBUS_STRUCT_END_CHAR_AS_STRING;
+}
+
template<typename U, typename V>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
- std::pair<U, V>* value) {
+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 variant_reader(nullptr);
dbus::MessageReader struct_reader(nullptr);
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
!reader->PopStruct(&struct_reader))
return false;
- return PopValueFromReader(&struct_reader, &value->first) &&
- PopValueFromReader(&struct_reader, &value->second);
+ // 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);
}
-// std::map = D-Bus ARRAY of DICT_ENTRY.
-template<typename KEY, typename VALUE>
-inline bool PopValueFromReader(dbus::MessageReader* reader,
- std::map<KEY, VALUE>* value) {
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<pair<U, V>> 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<bool inner_type_supported, typename U, typename V>
+struct DBusPairType {
+ // Returns "(UV)", where "U" and "V" are the signature strings for types U, V.
+ inline static std::string GetSignature() {
+ return GetStructDBusSignature<U, V>();
+ }
+ 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::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(details::GetDBusDictEntryType<KEY, VALUE>(), &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 variant_reader(nullptr);
dbus::MessageReader array_reader(nullptr);
if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
@@ -445,20 +665,101 @@
return false;
KEY key;
VALUE data;
- if (!PopValueFromReader(&dict_entry_reader, &key) ||
- !PopValueFromReader(&dict_entry_reader, &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->insert(std::make_pair(std::move(key), std::move(data)));
+ value->emplace(std::move(key), std::move(data));
}
return true;
}
-// google::protobuf::MessageLite = D-Bus ARRAY of BYTE
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<map<K, V>> 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<bool inner_types_supported,
+ typename KEY, typename VALUE, typename PRED, typename ALLOC>
+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<KEY, VALUE>());
+ }
+ 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);
}
+template<>
+struct DBusType<google::protobuf::MessageLite> {
+ inline static std::string GetSignature() {
+ return GetDBusSignature<std::vector<uint8_t>>();
+ }
+ inline static void Write(dbus::MessageWriter* writer,
+ const google::protobuf::MessageLite& value) {
+ AppendValueToWriter(writer, value);
+ }
+ inline static bool Read(dbus::MessageReader* reader,
+ google::protobuf::MessageLite* 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) {
+ std::string data_type = GetDBusSignature<T>();
+ dbus::MessageWriter variant_writer(nullptr);
+ writer->OpenVariant(data_type, &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 chromeos::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.
@@ -467,12 +768,17 @@
// 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>
-inline bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value) {
+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;
- return PopValueFromReader(&variant_reader, value);
+ // 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.
diff --git a/chromeos/dbus/data_serialization_unittest.cc b/chromeos/dbus/data_serialization_unittest.cc
index 4a465af..d10e8c8 100644
--- a/chromeos/dbus/data_serialization_unittest.cc
+++ b/chromeos/dbus/data_serialization_unittest.cc
@@ -19,6 +19,56 @@
namespace chromeos {
namespace dbus_utils {
+TEST(DBusUtils, Supported_BasicTypes) {
+ EXPECT_TRUE(IsTypeSupported<bool>::value);
+ EXPECT_TRUE(IsTypeSupported<uint8_t>::value);
+ EXPECT_TRUE(IsTypeSupported<int16_t>::value);
+ EXPECT_TRUE(IsTypeSupported<uint16_t>::value);
+ EXPECT_TRUE(IsTypeSupported<int32_t>::value);
+ EXPECT_TRUE(IsTypeSupported<uint32_t>::value);
+ EXPECT_TRUE(IsTypeSupported<int64_t>::value);
+ EXPECT_TRUE(IsTypeSupported<uint64_t>::value);
+ EXPECT_TRUE(IsTypeSupported<double>::value);
+ EXPECT_TRUE(IsTypeSupported<std::string>::value);
+ EXPECT_TRUE(IsTypeSupported<ObjectPath>::value);
+ EXPECT_TRUE(IsTypeSupported<FileDescriptor>::value);
+ EXPECT_TRUE(IsTypeSupported<Any>::value);
+}
+
+TEST(DBusUtils, Unsupported_BasicTypes) {
+ EXPECT_FALSE(IsTypeSupported<char>::value);
+ EXPECT_FALSE(IsTypeSupported<float>::value);
+}
+
+TEST(DBusUtils, Supported_ComplexTypes) {
+ EXPECT_TRUE(IsTypeSupported<std::vector<bool>>::value);
+ EXPECT_TRUE(IsTypeSupported<std::vector<uint8_t>>::value);
+ EXPECT_TRUE((IsTypeSupported<std::pair<int16_t, double>>::value));
+ EXPECT_TRUE((IsTypeSupported<std::map<uint16_t,
+ std::vector<int64_t>>>::value));
+}
+
+TEST(DBusUtils, Unsupported_ComplexTypes) {
+ EXPECT_FALSE(IsTypeSupported<std::vector<char>>::value);
+ EXPECT_FALSE((IsTypeSupported<std::pair<int16_t, float>>::value));
+ EXPECT_FALSE((IsTypeSupported<std::pair<char, int32_t>>::value));
+ EXPECT_FALSE((IsTypeSupported<std::map<int16_t, float>>::value));
+ EXPECT_FALSE((IsTypeSupported<std::map<char, int32_t>>::value));
+}
+
+TEST(DBusUtils, Supported_TypeSet) {
+ EXPECT_TRUE((IsTypeSupported<int32_t, double, std::string>::value));
+ EXPECT_TRUE((IsTypeSupported<bool, std::vector<int32_t>, uint8_t>::value));
+}
+
+TEST(DBusUtils, Unupported_TypeSet) {
+ EXPECT_FALSE((IsTypeSupported<int32_t, double, std::string, char>::value));
+ EXPECT_FALSE(
+ (IsTypeSupported<bool, std::pair<std::vector<float>, uint8_t>>::value));
+ EXPECT_FALSE((IsTypeSupported<char, double, std::string, int16_t>::value));
+ EXPECT_FALSE((IsTypeSupported<char, std::vector<float>, float>::value));
+}
+
TEST(DBusUtils, Signatures_BasicTypes) {
EXPECT_EQ("b", GetDBusSignature<bool>());
EXPECT_EQ("y", GetDBusSignature<uint8_t>());
@@ -74,7 +124,7 @@
TEST(DBusUtils, AppendAndPopByte) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(AppendValueToWriter(&writer, uint8_t{123}));
+ AppendValueToWriter(&writer, uint8_t{123});
EXPECT_EQ("y", message->GetSignature());
MessageReader reader(message.get());
@@ -100,17 +150,17 @@
MessageWriter writer(message.get());
// Append 0, true, 2, 3, 4, 5, 6, 7, 8.0, "string", "/object/path".
- EXPECT_TRUE(AppendValueToWriter(&writer, uint8_t{0}));
- EXPECT_TRUE(AppendValueToWriter(&writer, bool{true}));
- EXPECT_TRUE(AppendValueToWriter(&writer, int16_t{2}));
- EXPECT_TRUE(AppendValueToWriter(&writer, uint16_t{3}));
- EXPECT_TRUE(AppendValueToWriter(&writer, int32_t{4}));
- EXPECT_TRUE(AppendValueToWriter(&writer, uint32_t{5}));
- EXPECT_TRUE(AppendValueToWriter(&writer, int64_t{6}));
- EXPECT_TRUE(AppendValueToWriter(&writer, uint64_t{7}));
- EXPECT_TRUE(AppendValueToWriter(&writer, double{8.0}));
- EXPECT_TRUE(AppendValueToWriter(&writer, std::string{"string"}));
- EXPECT_TRUE(AppendValueToWriter(&writer, ObjectPath{"/object/path"}));
+ AppendValueToWriter(&writer, uint8_t{0});
+ AppendValueToWriter(&writer, bool{true});
+ AppendValueToWriter(&writer, int16_t{2});
+ AppendValueToWriter(&writer, uint16_t{3});
+ AppendValueToWriter(&writer, int32_t{4});
+ AppendValueToWriter(&writer, uint32_t{5});
+ AppendValueToWriter(&writer, int64_t{6});
+ AppendValueToWriter(&writer, uint64_t{7});
+ AppendValueToWriter(&writer, double{8.0});
+ AppendValueToWriter(&writer, std::string{"string"});
+ AppendValueToWriter(&writer, ObjectPath{"/object/path"});
EXPECT_EQ("ybnqiuxtdso", message->GetSignature());
@@ -172,7 +222,7 @@
// NB: thread IO requirements not relevant for unit tests.
temp.CheckValidity();
EXPECT_TRUE(temp.is_valid());
- EXPECT_TRUE(AppendValueToWriter(&writer, temp));
+ AppendValueToWriter(&writer, temp);
EXPECT_EQ("h", message->GetSignature());
@@ -193,18 +243,18 @@
MessageWriter writer(message.get());
// Append 10, false, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint8_t{10}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, bool{false}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int16_t{12}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint16_t{13}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int32_t{14}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint32_t{15}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int64_t{16}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, uint64_t{17}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, double{18.5}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, std::string{"data"}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"}));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, Any{17}));
+ AppendValueToWriterAsVariant(&writer, uint8_t{10});
+ AppendValueToWriterAsVariant(&writer, bool{false});
+ AppendValueToWriterAsVariant(&writer, int16_t{12});
+ AppendValueToWriterAsVariant(&writer, uint16_t{13});
+ AppendValueToWriterAsVariant(&writer, int32_t{14});
+ AppendValueToWriterAsVariant(&writer, uint32_t{15});
+ AppendValueToWriterAsVariant(&writer, int64_t{16});
+ AppendValueToWriterAsVariant(&writer, uint64_t{17});
+ AppendValueToWriterAsVariant(&writer, double{18.5});
+ AppendValueToWriterAsVariant(&writer, std::string{"data"});
+ AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"});
+ AppendValueToWriterAsVariant(&writer, Any{17});
EXPECT_EQ("vvvvvvvvvvvv", message->GetSignature());
@@ -257,18 +307,17 @@
MessageWriter writer(message.get());
// Append 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint8_t{10})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(bool{true})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(int16_t{12})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint16_t{13})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(int32_t{14})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint32_t{15})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(int64_t{16})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(uint64_t{17})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(double{18.5})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(std::string{"data"})));
- EXPECT_TRUE(AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"})));
-
+ AppendValueToWriter(&writer, Any(uint8_t{10}));
+ AppendValueToWriter(&writer, Any(bool{true}));
+ AppendValueToWriter(&writer, Any(int16_t{12}));
+ AppendValueToWriter(&writer, Any(uint16_t{13}));
+ AppendValueToWriter(&writer, Any(int32_t{14}));
+ AppendValueToWriter(&writer, Any(uint32_t{15}));
+ AppendValueToWriter(&writer, Any(int64_t{16}));
+ AppendValueToWriter(&writer, Any(uint64_t{17}));
+ AppendValueToWriter(&writer, Any(double{18.5}));
+ AppendValueToWriter(&writer, Any(std::string{"data"}));
+ AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"}));
EXPECT_EQ("vvvvvvvvvvv", message->GetSignature());
Any byte_value;
@@ -316,7 +365,7 @@
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
std::vector<uint8_t> bytes{1, 2, 3};
- EXPECT_TRUE(AppendValueToWriter(&writer, bytes));
+ AppendValueToWriter(&writer, bytes);
EXPECT_EQ("ay", message->GetSignature());
@@ -331,7 +380,7 @@
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
std::vector<uint8_t> bytes;
- EXPECT_TRUE(AppendValueToWriter(&writer, bytes));
+ AppendValueToWriter(&writer, bytes);
EXPECT_EQ("ay", message->GetSignature());
@@ -346,7 +395,7 @@
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
std::vector<std::string> strings{"foo", "bar", "baz"};
- EXPECT_TRUE(AppendValueToWriter(&writer, strings));
+ AppendValueToWriter(&writer, strings);
EXPECT_EQ("as", message->GetSignature());
@@ -363,7 +412,7 @@
std::vector<int64_t> values{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::max()};
- EXPECT_TRUE(AppendValueToWriter(&writer, values));
+ AppendValueToWriter(&writer, values);
EXPECT_EQ("ax", message->GetSignature());
@@ -382,7 +431,7 @@
ObjectPath("/object/path/2"),
ObjectPath("/object/path/3"),
};
- EXPECT_TRUE(AppendValueToWriter(&writer, object_paths));
+ AppendValueToWriter(&writer, object_paths);
EXPECT_EQ("ao", message->GetSignature());
@@ -401,11 +450,11 @@
std::vector<double> dbl_array_empty{};
std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
VariantDictionary dict_sv{{"k1", 1}, {"k2", "v2"}};
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, int_array));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, str_array));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dbl_array_empty));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_ss));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_sv));
+ AppendValueToWriterAsVariant(&writer, int_array);
+ AppendValueToWriterAsVariant(&writer, str_array);
+ AppendValueToWriterAsVariant(&writer, dbl_array_empty);
+ AppendValueToWriterAsVariant(&writer, dict_ss);
+ AppendValueToWriterAsVariant(&writer, dict_sv);
EXPECT_EQ("vvvvv", message->GetSignature());
@@ -449,7 +498,7 @@
{"keyA", std::string{"data"}},
{"keyB", ObjectPath{"/obj/path"}},
};
- EXPECT_TRUE(AppendValueToWriter(&writer, values));
+ AppendValueToWriter(&writer, values);
EXPECT_EQ("a{sv}", message->GetSignature());
@@ -492,7 +541,7 @@
{"key4", "value4"},
{"key5", "value5"},
};
- EXPECT_TRUE(AppendValueToWriter(&writer, values));
+ AppendValueToWriter(&writer, values);
EXPECT_EQ("a{ss}", message->GetSignature());
@@ -507,9 +556,9 @@
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
std::pair<std::string, int> struct1{"value2", 3};
- EXPECT_TRUE(AppendValueToWriter(&writer, struct1));
+ AppendValueToWriter(&writer, struct1);
std::pair<int, std::pair<int, int>> struct2{1, {2, 3}};
- EXPECT_TRUE(AppendValueToWriter(&writer, struct2));
+ AppendValueToWriter(&writer, struct2);
EXPECT_EQ("(si)(i(ii))", message->GetSignature());
@@ -530,11 +579,11 @@
std::vector<std::string> str_array{"foo", "bar", "baz"};
std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
VariantDictionary dict_sv{{"k1", "v1"}, {"k2", "v2"}};
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, 123));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, str_array));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, 1.7));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, dict_ss));
- EXPECT_TRUE(AppendValueToWriter(&writer, dict_sv));
+ AppendValueToWriterAsVariant(&writer, 123);
+ AppendValueToWriterAsVariant(&writer, str_array);
+ AppendValueToWriterAsVariant(&writer, 1.7);
+ AppendValueToWriterAsVariant(&writer, dict_ss);
+ AppendValueToWriter(&writer, dict_sv);
EXPECT_EQ("vvvva{sv}", message->GetSignature());
@@ -573,20 +622,14 @@
}
};
-// Specialize DBusSignature<T>::get() for "Person" structure.
-template<> struct DBusSignature<Person> {
- static std::string get() { return "(ssi)"; }
-};
-
// Overload AppendValueToWriter() for "Person" structure.
-bool AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) {
+void AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) {
dbus::MessageWriter struct_writer(nullptr);
writer->OpenStruct(&struct_writer);
- bool success = AppendValueToWriter(&struct_writer, value.first_name) &&
- AppendValueToWriter(&struct_writer, value.last_name) &&
- AppendValueToWriter(&struct_writer, value.age);
+ AppendValueToWriter(&struct_writer, value.first_name);
+ AppendValueToWriter(&struct_writer, value.last_name);
+ AppendValueToWriter(&struct_writer, value.age);
writer->CloseContainer(&struct_writer);
- return success;
}
// Overload PopValueFromReader() for "Person" structure.
@@ -601,13 +644,27 @@
PopValueFromReader(&struct_reader, &value->age);
}
+// Specialize DBusType<T> for "Person" structure.
+template<>
+struct DBusType<Person> {
+ inline static std::string GetSignature() {
+ return GetStructDBusSignature<std::string, std::string, int>();
+ }
+ inline static void Write(dbus::MessageWriter* writer, const Person& value) {
+ AppendValueToWriter(writer, value);
+ }
+ inline static bool Read(dbus::MessageReader* reader, Person* value) {
+ return PopValueFromReader(reader, value);
+ }
+};
+
TEST(DBusUtils, CustomStruct) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
- EXPECT_TRUE(AppendValueToWriter(&writer, people));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, people));
- EXPECT_TRUE(AppendValueToWriterAsVariant(&writer, people));
+ AppendValueToWriter(&writer, people);
+ AppendValueToWriterAsVariant(&writer, people);
+ AppendValueToWriterAsVariant(&writer, people);
EXPECT_EQ("a(ssi)vv", message->GetSignature());
@@ -626,5 +683,42 @@
EXPECT_EQ(people, people_out3);
}
+TEST(DBusUtils, CustomStructInComplexTypes) {
+ std::unique_ptr<Response> message(Response::CreateEmpty().release());
+ MessageWriter writer(message.get());
+ std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
+ std::vector<std::map<int, Person>> data{
+ {
+ {1, Person{"John", "Doe", 32}},
+ {2, Person{"Jane", "Smith", 48}},
+ }
+ };
+ AppendValueToWriter(&writer, data);
+
+ EXPECT_EQ("aa{i(ssi)}", message->GetSignature());
+
+ std::vector<std::map<int, Person>> data_out;;
+
+ MessageReader reader(message.get());
+ EXPECT_TRUE(PopValueFromReader(&reader, &data_out));
+ EXPECT_FALSE(reader.HasMoreData());
+
+ EXPECT_EQ(data, data_out);
+}
+
+TEST(DBusUtils, EmptyVariant) {
+ std::unique_ptr<Response> message(Response::CreateEmpty().release());
+ MessageWriter writer(message.get());
+ EXPECT_DEATH(AppendValueToWriter(&writer, Any{}),
+ "Must not be called on an empty Any");
+}
+
+TEST(DBusUtils, IncompatibleVariant) {
+ std::unique_ptr<Response> message(Response::CreateEmpty().release());
+ MessageWriter writer(message.get());
+ EXPECT_DEATH(AppendValueToWriter(&writer, Any{2.2f}),
+ "Type 'float' is not supported by D-Bus");
+}
+
} // namespace dbus_utils
} // namespace chromeos
diff --git a/chromeos/dbus/dbus_param_reader.h b/chromeos/dbus/dbus_param_reader.h
index 361713b..429ac48 100644
--- a/chromeos/dbus/dbus_param_reader.h
+++ b/chromeos/dbus/dbus_param_reader.h
@@ -90,7 +90,7 @@
// The variable to hold the value of the current parameter we reading from
// the message buffer.
ParamValueType current_param;
- if (!PopValueFromReader(reader, ¤t_param)) {
+ if (!DBusType<ParamValueType>::Read(reader, ¤t_param)) {
Error::AddTo(error, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS,
"Method parameter type mismatch");
return false;
diff --git a/chromeos/dbus/dbus_param_writer.h b/chromeos/dbus/dbus_param_writer.h
index 8805fd0..40e2263 100644
--- a/chromeos/dbus/dbus_param_writer.h
+++ b/chromeos/dbus/dbus_param_writer.h
@@ -25,31 +25,32 @@
// Generic writer method that takes 1 or more arguments. It recursively calls
// itself (each time with one fewer arguments) until no more is left.
template<typename ParamType, typename... RestOfParams>
- static bool Append(dbus::MessageWriter* writer,
+ static void Append(dbus::MessageWriter* writer,
const ParamType& param,
const RestOfParams&... rest) {
// Append the current |param| to D-Bus, then call Append() with one
// fewer arguments, until none is left and stand-alone version of
// Append(dbus::MessageWriter*) is called to end the iteration.
- return AppendValueToWriter(writer, param) && Append(writer, rest...);
+ DBusType<ParamType>::Write(writer, param);
+ Append(writer, rest...);
}
// The final overload of DBusParamWriter::Append() used when no more
// parameters are remaining to be written.
// Does nothing and finishes meta-recursion.
- static bool Append(dbus::MessageWriter* writer) { return true; }
+ static void Append(dbus::MessageWriter* writer) {}
// Generic writer method that takes 1 or more arguments. It recursively calls
// itself (each time with one fewer arguments) until no more is left.
// Handles non-pointer parameter by just skipping over it.
template<typename ParamType, typename... RestOfParams>
- static bool AppendDBusOutParams(dbus::MessageWriter* writer,
+ static void AppendDBusOutParams(dbus::MessageWriter* writer,
const ParamType& param,
const RestOfParams&... rest) {
// Skip the current |param| and call Append() with one fewer arguments,
// until none is left and stand-alone version of
// AppendDBusOutParams(dbus::MessageWriter*) is called to end the iteration.
- return AppendDBusOutParams(writer, rest...);
+ AppendDBusOutParams(writer, rest...);
}
// Generic writer method that takes 1 or more arguments. It recursively calls
@@ -57,20 +58,20 @@
// Handles only a parameter of pointer type and writes the data pointed to
// to the output message buffer.
template<typename ParamType, typename... RestOfParams>
- static bool AppendDBusOutParams(dbus::MessageWriter* writer,
+ static void AppendDBusOutParams(dbus::MessageWriter* writer,
ParamType* param,
const RestOfParams&... rest) {
// Append the current |param| to D-Bus, then call Append() with one
// fewer arguments, until none is left and stand-alone version of
// Append(dbus::MessageWriter*) is called to end the iteration.
- return AppendValueToWriter(writer, *param) &&
- AppendDBusOutParams(writer, rest...);
+ DBusType<ParamType>::Write(writer, *param);
+ AppendDBusOutParams(writer, rest...);
}
// The final overload of DBusParamWriter::AppendDBusOutParams() used when no
// more parameters are remaining to be written.
// Does nothing and finishes meta-recursion.
- static bool AppendDBusOutParams(dbus::MessageWriter* writer) { return true; }
+ static void AppendDBusOutParams(dbus::MessageWriter* writer) {}
};
} // namespace dbus_utils
diff --git a/chromeos/dbus/dbus_param_writer_unittest.cc b/chromeos/dbus/dbus_param_writer_unittest.cc
index 7d0ed53..cdedf5e 100644
--- a/chromeos/dbus/dbus_param_writer_unittest.cc
+++ b/chromeos/dbus/dbus_param_writer_unittest.cc
@@ -20,18 +20,18 @@
TEST(DBusParamWriter, Append_NoArgs) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(DBusParamWriter::Append(&writer));
+ DBusParamWriter::Append(&writer);
EXPECT_EQ("", message->GetSignature());
}
TEST(DBusParamWriter, Append_OneArg) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(DBusParamWriter::Append(&writer, int32_t{2}));
+ DBusParamWriter::Append(&writer, int32_t{2});
EXPECT_EQ("i", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::Append(&writer, std::string{"foo"}));
+ DBusParamWriter::Append(&writer, std::string{"foo"});
EXPECT_EQ("is", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::Append(&writer, ObjectPath{"/o"}));
+ DBusParamWriter::Append(&writer, ObjectPath{"/o"});
EXPECT_EQ("iso", message->GetSignature());
int32_t int_value = 0;
@@ -51,7 +51,7 @@
TEST(DBusParamWriter, Append_ManyArgs) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(DBusParamWriter::Append(&writer, int32_t{9}, Any{7.5}, true));
+ DBusParamWriter::Append(&writer, int32_t{9}, Any{7.5}, true);
EXPECT_EQ("ivb", message->GetSignature());
int32_t int_value = 0;
@@ -68,18 +68,10 @@
EXPECT_TRUE(bool_value);
}
-TEST(DBusParamWriter, Append_UnsupportedType) {
- std::unique_ptr<Response> message(Response::CreateEmpty().release());
- MessageWriter writer(message.get());
- // 'char' (AKA int8_t) is not supported by D-Bus.
- EXPECT_FALSE(DBusParamWriter::Append(&writer, char{'s'}));
- EXPECT_EQ("", message->GetSignature());
-}
-
TEST(DBusParamWriter, AppendDBusOutParams_NoArgs) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer));
+ DBusParamWriter::AppendDBusOutParams(&writer);
EXPECT_EQ("", message->GetSignature());
}
@@ -90,11 +82,11 @@
std::string string_value_in{"bar"};
ObjectPath path_value_in{"/obj/path"};
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &int_value_in));
+ DBusParamWriter::AppendDBusOutParams(&writer, &int_value_in);
EXPECT_EQ("i", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &string_value_in));
+ DBusParamWriter::AppendDBusOutParams(&writer, &string_value_in);
EXPECT_EQ("is", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &path_value_in));
+ DBusParamWriter::AppendDBusOutParams(&writer, &path_value_in);
EXPECT_EQ("iso", message->GetSignature());
int32_t int_value = 0;
@@ -117,10 +109,10 @@
int32_t int_value_in{8};
Any variant_value_in{8.5};
bool bool_value_in{true};
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer,
- &int_value_in,
- &variant_value_in,
- &bool_value_in));
+ DBusParamWriter::AppendDBusOutParams(&writer,
+ &int_value_in,
+ &variant_value_in,
+ &bool_value_in);
EXPECT_EQ("ivb", message->GetSignature());
int32_t int_value = 0;
@@ -140,7 +132,7 @@
TEST(DBusParamWriter, AppendDBusOutParams_Mixed_NoArgs) {
std::unique_ptr<Response> message(Response::CreateEmpty().release());
MessageWriter writer(message.get());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 3, 5));
+ DBusParamWriter::AppendDBusOutParams(&writer, 3, 5);
EXPECT_EQ("", message->GetSignature());
}
@@ -151,12 +143,11 @@
std::string str_value_in{"bar"};
ObjectPath path_value_in{"/obj"};
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 2, &int_value_in));
+ DBusParamWriter::AppendDBusOutParams(&writer, 2, &int_value_in);
EXPECT_EQ("i", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, &str_value_in, 0));
+ DBusParamWriter::AppendDBusOutParams(&writer, &str_value_in, 0);
EXPECT_EQ("is", message->GetSignature());
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer, 1, &path_value_in,
- 2));
+ DBusParamWriter::AppendDBusOutParams(&writer, 1, &path_value_in, 2);
EXPECT_EQ("iso", message->GetSignature());
int32_t int_value = 0;
@@ -179,14 +170,14 @@
int32_t int_value_in{8};
Any variant_value_in{7.5};
bool bool_value_in{true};
- EXPECT_TRUE(DBusParamWriter::AppendDBusOutParams(&writer,
- 0,
- &int_value_in,
- 1,
- &variant_value_in,
- 2,
- &bool_value_in,
- 3));
+ DBusParamWriter::AppendDBusOutParams(&writer,
+ 0,
+ &int_value_in,
+ 1,
+ &variant_value_in,
+ 2,
+ &bool_value_in,
+ 3);
EXPECT_EQ("ivb", message->GetSignature());
int32_t int_value = 0;
diff --git a/chromeos/dbus/dbus_signal.h b/chromeos/dbus/dbus_signal.h
index 17e7442..ed7e129 100644
--- a/chromeos/dbus/dbus_signal.h
+++ b/chromeos/dbus/dbus_signal.h
@@ -54,8 +54,8 @@
bool Send(const Args&... args) const {
dbus::Signal signal(interface_name_, signal_name_);
dbus::MessageWriter signal_writer(&signal);
- return DBusParamWriter::Append(&signal_writer, args...) &&
- SendSignal(&signal);
+ DBusParamWriter::Append(&signal_writer, args...);
+ return SendSignal(&signal);
}
private: