// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ #include // For |memcpy()|. #include #include "mojo/public/c/system/macros.h" #include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/lib/string_serialization.h" #include "mojo/public/cpp/bindings/lib/template_util.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" namespace mojo { template inline size_t GetSerializedSize_(const Array& input); // Because ValidateParams requires explicit argument specification, the // argument-dependent loopup technique used to omit namespace when calling // Serialize_() doesn't seem to work. Therefore, this function is named // differently from those Serialize_() overloads. template inline void SerializeArray_(Array input, internal::Buffer* buf, internal::Array_Data** output); template inline void Deserialize_(internal::Array_Data* data, Array* output); namespace internal { template ::value> struct ArraySerializer; template struct ArraySerializer { MOJO_COMPILE_ASSERT(sizeof(E) == sizeof(F), wrong_array_serializer); static size_t GetSerializedSize(const Array& input) { return sizeof(Array_Data) + Align(input.size() * sizeof(E)); } template static void SerializeElements( Array input, Buffer* buf, Array_Data* output) { MOJO_COMPILE_ASSERT(!element_is_nullable, Primitive_type_should_be_non_nullable); MOJO_COMPILE_ASSERT( (IsSame::value), Primitive_type_should_not_have_array_validate_params); memcpy(output->storage(), &input.storage()[0], input.size() * sizeof(E)); } static void DeserializeElements( Array_Data* input, Array* output) { std::vector result(input->size()); memcpy(&result[0], input->storage(), input->size() * sizeof(E)); output->Swap(&result); } }; template <> struct ArraySerializer { static size_t GetSerializedSize(const Array& input) { return sizeof(Array_Data) + Align((input.size() + 7) / 8); } template static void SerializeElements( Array input, Buffer* buf, Array_Data* output) { MOJO_COMPILE_ASSERT(!element_is_nullable, Primitive_type_should_be_non_nullable); MOJO_COMPILE_ASSERT( (IsSame::value), Primitive_type_should_not_have_array_validate_params); // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? for (size_t i = 0; i < input.size(); ++i) output->at(i) = input[i]; } static void DeserializeElements( Array_Data* input, Array* output) { Array result(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) result.at(i) = input->at(i); output->Swap(&result); } }; template struct ArraySerializer, H, true> { static size_t GetSerializedSize(const Array >& input) { return sizeof(Array_Data) + Align(input.size() * sizeof(H)); } template static void SerializeElements(Array > input, Buffer* buf, Array_Data* output) { MOJO_COMPILE_ASSERT( (IsSame::value), Handle_type_should_not_have_array_validate_params); for (size_t i = 0; i < input.size(); ++i) { output->at(i) = input[i].release(); // Transfer ownership of the handle. MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( !element_is_nullable && !output->at(i).is_valid(), VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, MakeMessageWithArrayIndex( "invalid handle in array expecting valid handles", input.size(), i)); } } static void DeserializeElements( Array_Data* input, Array >* output) { Array > result(input->size()); for (size_t i = 0; i < input->size(); ++i) result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i))); output->Swap(&result); } }; template struct ArraySerializer { static size_t GetSerializedSize(const Array& input) { size_t size = sizeof(Array_Data) + input.size() * sizeof(internal::StructPointer); for (size_t i = 0; i < input.size(); ++i) size += GetSerializedSize_(input[i]); return size; } template static void SerializeElements(Array input, Buffer* buf, Array_Data* output) { for (size_t i = 0; i < input.size(); ++i) { typename S::Data_* element; SerializeCaller::Run( input[i].Pass(), buf, &element); output->at(i) = element; MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( !element_is_nullable && !element, VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, MakeMessageWithArrayIndex( "null in array expecting valid pointers", input.size(), i)); } } static void DeserializeElements( Array_Data* input, Array* output) { Array result(input->size()); for (size_t i = 0; i < input->size(); ++i) { S element; Deserialize_(input->at(i), &element); result[i] = element.Pass(); } output->Swap(&result); } private: template struct SerializeCaller { static void Run(T input, Buffer* buf, typename T::Data_** output) { MOJO_COMPILE_ASSERT((IsSame::value), Struct_type_should_not_have_array_validate_params); Serialize_(input.Pass(), buf, output); } }; template struct SerializeCaller, Params> { static void Run(Array input, Buffer* buf, typename Array::Data_** output) { SerializeArray_(input.Pass(), buf, output); } }; }; template <> struct ArraySerializer { static size_t GetSerializedSize(const Array& input) { size_t size = sizeof(Array_Data) + input.size() * sizeof(internal::StringPointer); for (size_t i = 0; i < input.size(); ++i) size += GetSerializedSize_(input[i]); return size; } template static void SerializeElements( Array input, Buffer* buf, Array_Data* output) { MOJO_COMPILE_ASSERT( (IsSame >::value), String_type_has_unexpected_array_validate_params); for (size_t i = 0; i < input.size(); ++i) { String_Data* element; Serialize_(input[i], buf, &element); output->at(i) = element; MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( !element_is_nullable && !element, VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, MakeMessageWithArrayIndex( "null in array expecting valid strings", input.size(), i)); } } static void DeserializeElements( Array_Data* input, Array* output) { Array result(input->size()); for (size_t i = 0; i < input->size(); ++i) Deserialize_(input->at(i), &result[i]); output->Swap(&result); } }; } // namespace internal template inline size_t GetSerializedSize_(const Array& input) { if (!input) return 0; typedef typename internal::WrapperTraits::DataType F; return internal::ArraySerializer::GetSerializedSize(input); } template inline void SerializeArray_(Array input, internal::Buffer* buf, internal::Array_Data** output) { if (input) { MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( ValidateParams::expected_num_elements != 0 && input.size() != ValidateParams::expected_num_elements, internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, internal::MakeMessageWithExpectedArraySize( "fixed-size array has wrong number of elements", input.size(), ValidateParams::expected_num_elements)); internal::Array_Data* result = internal::Array_Data::New(input.size(), buf); if (result) { internal::ArraySerializer::template SerializeElements< ValidateParams::element_is_nullable, typename ValidateParams::ElementValidateParams>( internal::Forward(input), buf, result); } *output = result; } else { *output = NULL; } } template inline void Deserialize_(internal::Array_Data* input, Array* output) { if (input) { internal::ArraySerializer::DeserializeElements(input, output); } else { output->reset(); } } } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_