Index: mojo/public/cpp/bindings/lib/array_serialization.h |
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h |
index 91fa5d71b8cd1e394f57767429a6a11ba5f3e8b1..1961a0bbec2bb09abef66333f249af7195415db4 100644 |
--- a/mojo/public/cpp/bindings/lib/array_serialization.h |
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h |
@@ -6,39 +6,395 @@ |
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ |
#include <stddef.h> |
+#include <string.h> // For |memcpy()|. |
-#include "mojo/public/cpp/bindings/array.h" |
-#include "mojo/public/cpp/bindings/lib/array_serialization_traits.h" |
+#include <limits> |
+#include <type_traits> |
+#include <utility> |
+#include <vector> |
-namespace mojo { |
+#include "base/logging.h" |
+#include "mojo/public/cpp/bindings/lib/array_internal.h" |
+#include "mojo/public/cpp/bindings/lib/serialization_forward.h" |
+#include "mojo/public/cpp/bindings/lib/template_util.h" |
+#include "mojo/public/cpp/bindings/lib/validation_errors.h" |
-template <typename E> |
-inline size_t GetSerializedSize_(const Array<E>& input, |
- internal::SerializationContext* context) { |
- return internal::ArraySerializationImpl<Array<E>, |
- Array<E>>::GetSerializedSize(input, |
- context); |
+namespace WTF { |
+class String; |
} |
-template <typename E> |
-inline void SerializeArray_( |
- Array<E> input, |
- internal::Buffer* buf, |
- typename Array<E>::Data_** output, |
- const internal::ArrayValidateParams* validate_params, |
- internal::SerializationContext* context) { |
- return internal::ArraySerializationImpl<Array<E>, Array<E>>::Serialize( |
- std::move(input), buf, output, validate_params, context); |
-} |
+namespace mojo { |
+namespace internal { |
-template <typename E> |
-inline bool Deserialize_(typename Array<E>::Data_* input, |
- Array<E>* output, |
- internal::SerializationContext* context) { |
- return internal::ArraySerializationImpl<Array<E>, Array<E>>::Deserialize( |
- input, output, context); |
-} |
+enum class ArraySerializerType { |
+ BOOLEAN, |
+ // Except boolean. |
+ POD, |
+ HANDLE, |
+ // String, array, map and struct. |
+ POINTER, |
+ UNION |
+}; |
+ |
+template <typename T> |
+struct GetArraySerializerType { |
+ static const ArraySerializerType value = |
+ IsUnionDataType<T>::value |
+ ? ArraySerializerType::UNION |
+ : (std::is_pointer<T>::value |
+ ? ArraySerializerType::POINTER |
+ : (IsHandle<T>::value ? ArraySerializerType::HANDLE |
+ : (std::is_same<T, bool>::value |
+ ? ArraySerializerType::BOOLEAN |
+ : ArraySerializerType::POD))); |
+}; |
+ |
+template <typename MojomType, |
+ typename MaybeConstUserType, |
+ ArraySerializerType type = |
+ GetArraySerializerType<typename MojomType::Data_::Element>::value> |
+struct ArraySerializer; |
+ |
+// Handles serialization and deserialization of arrays of pod types. |
+template <typename MojomType, typename MaybeConstUserType> |
+struct ArraySerializer<MojomType, |
+ MaybeConstUserType, |
+ ArraySerializerType::POD> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Data = typename MojomType::Data_; |
+ using DataElement = typename Data::Element; |
+ using Element = typename MojomType::Element; |
+ using Traits = ArrayTraits<UserType>; |
+ |
+ static_assert(sizeof(Element) == sizeof(DataElement), |
+ "Incorrect array serializer"); |
+ static_assert(std::is_same<Element, typename Traits::Element>::value, |
+ "Incorrect array serializer"); |
+ |
+ static size_t GetSerializedSize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ return sizeof(Data) + Align(Traits::GetSize(input) * sizeof(DataElement)); |
+ } |
+ |
+ static void SerializeElements(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ DCHECK(!validate_params->element_is_nullable) |
+ << "Primitive type should be non-nullable"; |
+ DCHECK(!validate_params->element_validate_params) |
+ << "Primitive type should not have array validate params"; |
+ |
+ if (Traits::GetSize(input)) { |
+ memcpy(output->storage(), Traits::GetData(input), |
+ Traits::GetSize(input) * sizeof(DataElement)); |
+ } |
+ } |
+ |
+ static bool DeserializeElements(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ Traits::Resize(*output, input->size()); |
+ if (input->size()) { |
+ memcpy(Traits::GetData(*output), input->storage(), |
+ input->size() * sizeof(DataElement)); |
+ } |
+ return true; |
+ } |
+}; |
+ |
+// Serializes and deserializes arrays of bools. |
+template <typename MojomType, typename MaybeConstUserType> |
+struct ArraySerializer<MojomType, |
+ MaybeConstUserType, |
+ ArraySerializerType::BOOLEAN> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Traits = ArrayTraits<UserType>; |
+ using Data = typename MojomType::Data_; |
+ |
+ static_assert(std::is_same<bool, typename UserType::Element>::value, |
+ "Incorrect array serializer"); |
+ |
+ static size_t GetSerializedSize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ return sizeof(Data) + Align((Traits::GetSize(input) + 7) / 8); |
+ } |
+ |
+ static void SerializeElements(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ DCHECK(!validate_params->element_is_nullable) |
+ << "Primitive type should be non-nullable"; |
+ DCHECK(!validate_params->element_validate_params) |
+ << "Primitive type should not have array validate params"; |
+ |
+ // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? |
+ size_t size = Traits::GetSize(input); |
+ for (size_t i = 0; i < size; ++i) |
+ output->at(i) = Traits::GetAt(input, i); |
+ } |
+ static bool DeserializeElements(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ Traits::Resize(*output, input->size()); |
+ // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? |
+ for (size_t i = 0; i < input->size(); ++i) |
+ Traits::GetAt(*output, i) = input->at(i); |
+ return true; |
+ } |
+}; |
+ |
+// Serializes and deserializes arrays of handles. |
+template <typename MojomType, typename MaybeConstUserType> |
+struct ArraySerializer<MojomType, |
+ MaybeConstUserType, |
+ ArraySerializerType::HANDLE> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Data = typename MojomType::Data_; |
+ using Element = typename MojomType::Element; |
+ using Traits = ArrayTraits<UserType>; |
+ |
+ static_assert(std::is_same<Element, typename Traits::Element>::value, |
+ "Incorrect array serializer"); |
+ |
+ static size_t GetSerializedSize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ return sizeof(Data) + |
+ Align(Traits::GetSize(input) * sizeof(typename Data::Element)); |
+ } |
+ |
+ static void SerializeElements(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ DCHECK(!validate_params->element_validate_params) |
+ << "Handle type should not have array validate params"; |
+ |
+ size_t size = Traits::GetSize(input); |
+ for (size_t i = 0; i < size; ++i) { |
+ // Transfer ownership of the handle. |
+ output->at(i) = |
+ context->handles.AddHandle(Traits::GetAt(input, i).release()); |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ !validate_params->element_is_nullable && !output->at(i).is_valid(), |
+ VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, |
+ MakeMessageWithArrayIndex( |
+ "invalid handle in array expecting valid handles", size, i)); |
+ } |
+ } |
+ static bool DeserializeElements(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ using HandleType = typename Element::RawHandleType; |
+ Traits::Resize(*output, input->size()); |
+ for (size_t i = 0; i < input->size(); ++i) { |
+ Traits::GetAt(*output, i) = MakeScopedHandle( |
+ HandleType(context->handles.TakeHandle(input->at(i)).value())); |
+ } |
+ return true; |
+ } |
+}; |
+ |
+// This template must only apply to pointer mojo entity (strings, structs, |
+// arrays and maps). |
+template <typename MojomType, typename MaybeConstUserType> |
+struct ArraySerializer<MojomType, |
+ MaybeConstUserType, |
+ ArraySerializerType::POINTER> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Data = typename MojomType::Data_; |
+ using DataElement = typename Data::Element; |
+ using Element = typename MojomType::Element; |
+ using Traits = ArrayTraits<UserType>; |
+ |
+ static size_t GetSerializedSize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ size_t element_count = Traits::GetSize(input); |
+ size_t size = |
+ sizeof(Data) + |
+ element_count * |
+ sizeof(Pointer<typename std::remove_pointer<DataElement>::type>); |
+ for (size_t i = 0; i < element_count; ++i) |
+ size += PrepareToSerialize<Element>(Traits::GetAt(input, i), context); |
+ return size; |
+ } |
+ |
+ static void SerializeElements(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ size_t size = Traits::GetSize(input); |
+ for (size_t i = 0; i < size; ++i) { |
+ DataElement element; |
+ SerializeCaller<Element>::Run(Traits::GetAt(input, i), buf, &element, |
+ validate_params->element_validate_params, |
+ context); |
+ output->at(i) = element; |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ !validate_params->element_is_nullable && !element, |
+ VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
+ MakeMessageWithArrayIndex("null in array expecting valid pointers", |
+ size, i)); |
+ } |
+ } |
+ static bool DeserializeElements(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ bool success = true; |
+ Traits::Resize(*output, input->size()); |
+ for (size_t i = 0; i < input->size(); ++i) { |
+ // Note that we rely on complete deserialization taking place in order to |
+ // transfer ownership of all encoded handles. Therefore we don't |
+ // short-circuit on failure here. |
+ if (!Deserialize<Element>(input->at(i), &Traits::GetAt(*output, i), |
+ context)) { |
+ success = false; |
+ } |
+ } |
+ return success; |
+ } |
+ |
+ private: |
+ template <typename T, |
+ bool is_array_or_map = IsSpecializationOf<Array, T>::value || |
+ IsSpecializationOf<Map, T>::value> |
+ struct SerializeCaller { |
+ template <typename InputElementType> |
+ static void Run(InputElementType&& input, |
+ Buffer* buf, |
+ DataElement* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ Serialize<T>(std::forward<InputElementType>(input), buf, output, context); |
+ } |
+ }; |
+ |
+ template <typename T> |
+ struct SerializeCaller<T, true> { |
+ template <typename InputElementType> |
+ static void Run(InputElementType&& input, |
+ Buffer* buf, |
+ DataElement* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ Serialize<T>(std::forward<InputElementType>(input), buf, output, |
+ validate_params, context); |
+ } |
+ }; |
+}; |
+ |
+// Handles serialization and deserialization of arrays of unions. |
+template <typename MojomType, typename MaybeConstUserType> |
+struct ArraySerializer<MojomType, |
+ MaybeConstUserType, |
+ ArraySerializerType::UNION> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Data = typename MojomType::Data_; |
+ using Traits = ArrayTraits<UserType>; |
+ |
+ static_assert(std::is_same<typename MojomType::Element, |
+ typename Traits::Element>::value, |
+ "Incorrect array serializer"); |
+ |
+ static size_t GetSerializedSize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ size_t element_count = Traits::GetSize(input); |
+ size_t size = sizeof(Data); |
+ for (size_t i = 0; i < element_count; ++i) { |
+ // Call GetSerializedSize_ with |inlined| set to false, so that it will |
+ // account for both the data in the union and the space in the array used |
+ // to hold the union. |
+ size += GetSerializedSize_(Traits::GetAt(input, i), false, context); |
+ } |
+ return size; |
+ } |
+ |
+ static void SerializeElements(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data* output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ size_t size = Traits::GetSize(input); |
+ for (size_t i = 0; i < size; ++i) { |
+ typename Data::Element* result = output->storage() + i; |
+ SerializeUnion_(std::move(Traits::GetAt(input, i)), buf, &result, true, |
+ context); |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ !validate_params->element_is_nullable && output->at(i).is_null(), |
+ VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
+ MakeMessageWithArrayIndex("null in array expecting valid unions", |
+ size, i)); |
+ } |
+ } |
+ |
+ static bool DeserializeElements(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ bool success = true; |
+ Traits::Resize(*output, input->size()); |
+ for (size_t i = 0; i < input->size(); ++i) { |
+ // Note that we rely on complete deserialization taking place in order to |
+ // transfer ownership of all encoded handles. Therefore we don't |
+ // short-circuit on failure here. |
+ if (!Deserialize_(&input->at(i), &Traits::GetAt(*output, i), context)) |
+ success = false; |
+ } |
+ return success; |
+ } |
+}; |
+ |
+template <typename Element, typename MaybeConstUserType> |
+struct Serializer<Array<Element>, MaybeConstUserType> { |
+ using UserType = typename std::remove_const<MaybeConstUserType>::type; |
+ using Impl = ArraySerializer<Array<Element>, MaybeConstUserType>; |
+ using Traits = ArrayTraits<UserType>; |
+ using Data = typename Array<Element>::Data_; |
+ |
+ static size_t PrepareToSerialize(MaybeConstUserType& input, |
+ SerializationContext* context) { |
+ if (CallIsNullIfExists<Traits>(input)) |
+ return 0; |
+ return Impl::GetSerializedSize(input, context); |
+ } |
+ |
+ static void Serialize(MaybeConstUserType& input, |
+ Buffer* buf, |
+ Data** output, |
+ const ArrayValidateParams* validate_params, |
+ SerializationContext* context) { |
+ if (!CallIsNullIfExists<Traits>(input)) { |
+ MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( |
+ validate_params->expected_num_elements != 0 && |
+ Traits::GetSize(input) != validate_params->expected_num_elements, |
+ internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, |
+ internal::MakeMessageWithExpectedArraySize( |
+ "fixed-size array has wrong number of elements", |
+ Traits::GetSize(input), validate_params->expected_num_elements)); |
+ Data* result = Data::New(Traits::GetSize(input), buf); |
+ if (result) |
+ Impl::SerializeElements(input, buf, result, validate_params, context); |
+ *output = result; |
+ } else { |
+ *output = nullptr; |
+ } |
+ } |
+ |
+ static bool Deserialize(Data* input, |
+ UserType* output, |
+ SerializationContext* context) { |
+ if (input) |
+ return Impl::DeserializeElements(input, output, context); |
+ Traits::SetToNull(*output); |
+ return true; |
+ } |
+}; |
+} // namespace internal |
} // namespace mojo |
#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ |