| Index: mojo/public/cpp/bindings/lib/map_serialization.h | 
| diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h | 
| index 56ef68d3162f90f0ff73707fbb23e92f35ba6ae8..91e404e478abe9518e6790da88073fa4c70cc4c1 100644 | 
| --- a/mojo/public/cpp/bindings/lib/map_serialization.h | 
| +++ b/mojo/public/cpp/bindings/lib/map_serialization.h | 
| @@ -5,7 +5,10 @@ | 
| #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_ | 
| #define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_ | 
|  | 
| +#include <type_traits> | 
| + | 
| #include "mojo/public/cpp/bindings/array.h" | 
| +#include "mojo/public/cpp/bindings/lib/array_serialization.h" | 
| #include "mojo/public/cpp/bindings/lib/map_data_internal.h" | 
| #include "mojo/public/cpp/bindings/lib/serialization_forward.h" | 
| #include "mojo/public/cpp/bindings/map.h" | 
| @@ -13,44 +16,93 @@ | 
| namespace mojo { | 
| namespace internal { | 
|  | 
| -template <typename Key, typename Value> | 
| -struct MapContext { | 
| -  explicit MapContext(bool in_is_null) : is_null(in_is_null) {} | 
| +template <typename MaybeConstUserType> | 
| +class MapReaderBase { | 
| + public: | 
| +  using UserType = typename std::remove_const<MaybeConstUserType>::type; | 
| +  using Traits = MapTraits<UserType>; | 
| +  using MaybeConstIterator = | 
| +      decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>())); | 
| + | 
| +  explicit MapReaderBase(MaybeConstUserType& input) | 
| +      : input_(input), iter_(Traits::GetBegin(input_)) {} | 
| +  ~MapReaderBase() {} | 
| + | 
| +  size_t GetSize() const { return Traits::GetSize(input_); } | 
| + | 
| +  // Return null because key or value elements are not stored continuously in | 
| +  // memory. | 
| +  void* GetDataIfExists() { return nullptr; } | 
| + | 
| + protected: | 
| +  MaybeConstUserType& input_; | 
| +  MaybeConstIterator iter_; | 
| +}; | 
| + | 
| +// Used as the UserTypeReader template parameter of ArraySerializer. | 
| +template <typename MaybeConstUserType> | 
| +class MapKeyReader : public MapReaderBase<MaybeConstUserType> { | 
| + public: | 
| +  using Base = MapReaderBase<MaybeConstUserType>; | 
| +  using Traits = typename Base::Traits; | 
| + | 
| +  explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {} | 
| +  ~MapKeyReader() {} | 
|  | 
| -  bool is_null; | 
| -  Array<Key> keys; | 
| -  Array<Value> values; | 
| +  const typename Traits::Key& GetNext() { | 
| +    const typename Traits::Key& key = Traits::GetKey(this->iter_); | 
| +    Traits::AdvanceIterator(this->iter_); | 
| +    return key; | 
| +  } | 
| +}; | 
| + | 
| +// Used as the UserTypeReader template parameter of ArraySerializer. | 
| +template <typename MaybeConstUserType> | 
| +class MapValueReader : public MapReaderBase<MaybeConstUserType> { | 
| + public: | 
| +  using Base = MapReaderBase<MaybeConstUserType>; | 
| +  using Traits = typename Base::Traits; | 
| +  using MaybeConstIterator = typename Base::MaybeConstIterator; | 
| + | 
| +  explicit MapValueReader(MaybeConstUserType& input) : Base(input) {} | 
| +  ~MapValueReader() {} | 
| + | 
| +  using GetNextResult = | 
| +      decltype(Traits::GetValue(std::declval<MaybeConstIterator&>())); | 
| +  GetNextResult GetNext() { | 
| +    GetNextResult value = Traits::GetValue(this->iter_); | 
| +    Traits::AdvanceIterator(this->iter_); | 
| +    return value; | 
| +  } | 
| }; | 
|  | 
| template <typename Key, typename Value, typename MaybeConstUserType> | 
| struct Serializer<Map<Key, Value>, MaybeConstUserType> { | 
| using UserType = typename std::remove_const<MaybeConstUserType>::type; | 
| -  using UserKey = typename UserType::Key; | 
| -  using UserValue = typename UserType::Value; | 
| +  using Traits = MapTraits<UserType>; | 
| +  using UserKey = typename Traits::Key; | 
| +  using UserValue = typename Traits::Value; | 
| using Data = typename Map<Key, Value>::Data_; | 
| - | 
| -  static_assert(std::is_same<MaybeConstUserType, UserType>::value, | 
| -                "Only support serialization of non-const Maps."); | 
| -  static_assert(IsSpecializationOf<Map, UserType>::value, | 
| -                "Custom mapping of mojom map is not supported yet."); | 
| - | 
| -  static size_t PrepareToSerialize(UserType& input, | 
| +  using KeyArraySerializer = ArraySerializer<Array<Key>, | 
| +                                             Array<UserKey>, | 
| +                                             MapKeyReader<MaybeConstUserType>>; | 
| +  using ValueArraySerializer = | 
| +      ArraySerializer<Array<Value>, | 
| +                      Array<UserValue>, | 
| +                      MapValueReader<MaybeConstUserType>>; | 
| + | 
| +  static size_t PrepareToSerialize(MaybeConstUserType& input, | 
| SerializationContext* context) { | 
| -    auto map_context = new MapContext<UserKey, UserValue>(input.is_null()); | 
| -    if (!context->custom_contexts) | 
| -      context->custom_contexts.reset(new std::queue<void*>()); | 
| -    context->custom_contexts->push(map_context); | 
| - | 
| -    if (!input) | 
| +    if (CallIsNullIfExists<Traits>(input)) | 
| return 0; | 
|  | 
| -    input.DecomposeMapTo(&map_context->keys, &map_context->values); | 
| - | 
| size_t struct_overhead = sizeof(Data); | 
| +    MapKeyReader<MaybeConstUserType> key_reader(input); | 
| size_t keys_size = | 
| -        internal::PrepareToSerialize<Array<Key>>(map_context->keys, context); | 
| -    size_t values_size = internal::PrepareToSerialize<Array<Value>>( | 
| -        map_context->values, context); | 
| +        KeyArraySerializer::GetSerializedSize(&key_reader, context); | 
| +    MapValueReader<MaybeConstUserType> value_reader(input); | 
| +    size_t values_size = | 
| +        ValueArraySerializer::GetSerializedSize(&value_reader, context); | 
|  | 
| return struct_overhead + keys_size + values_size; | 
| } | 
| @@ -58,31 +110,36 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> { | 
| // We don't need an ArrayValidateParams instance for key validation since | 
| // we can deduce it from the Key type. (which can only be primitive types or | 
| // non-nullable strings.) | 
| -  static void Serialize(UserType& input, | 
| +  static void Serialize(MaybeConstUserType& input, | 
| Buffer* buf, | 
| Data** output, | 
| const ArrayValidateParams* value_validate_params, | 
| SerializationContext* context) { | 
| -    std::unique_ptr<MapContext<UserKey, UserValue>> map_context( | 
| -        static_cast<MapContext<UserKey, UserValue>*>( | 
| -            context->custom_contexts->front())); | 
| -    context->custom_contexts->pop(); | 
| - | 
| -    if (map_context->is_null) { | 
| +    if (CallIsNullIfExists<Traits>(input)) { | 
| *output = nullptr; | 
| return; | 
| } | 
|  | 
| auto result = Data::New(buf); | 
| if (result) { | 
| -      const ArrayValidateParams* key_validate_params = | 
| -          MapKeyValidateParamsFactory< | 
| -              typename GetDataTypeAsArrayElement<Key>::Data>::Get(); | 
| -      internal::Serialize<Array<Key>>(map_context->keys, buf, &result->keys.ptr, | 
| -                                      key_validate_params, context); | 
| -      internal::Serialize<Array<Value>>(map_context->values, buf, | 
| -                                        &result->values.ptr, | 
| -                                        value_validate_params, context); | 
| +      result->keys.ptr = Array<Key>::Data_::New(Traits::GetSize(input), buf); | 
| +      if (result->keys.ptr) { | 
| +        const ArrayValidateParams* key_validate_params = | 
| +            MapKeyValidateParamsFactory< | 
| +                typename GetDataTypeAsArrayElement<Key>::Data>::Get(); | 
| +        MapKeyReader<MaybeConstUserType> key_reader(input); | 
| +        KeyArraySerializer::SerializeElements( | 
| +            &key_reader, buf, result->keys.ptr, key_validate_params, context); | 
| +      } | 
| + | 
| +      result->values.ptr = | 
| +          Array<Value>::Data_::New(Traits::GetSize(input), buf); | 
| +      if (result->values.ptr) { | 
| +        MapValueReader<MaybeConstUserType> value_reader(input); | 
| +        ValueArraySerializer::SerializeElements(&value_reader, buf, | 
| +                                                result->values.ptr, | 
| +                                                value_validate_params, context); | 
| +      } | 
| } | 
| *output = result; | 
| } | 
| @@ -90,26 +147,26 @@ struct Serializer<Map<Key, Value>, MaybeConstUserType> { | 
| static bool Deserialize(Data* input, | 
| UserType* output, | 
| SerializationContext* context) { | 
| -    bool success = true; | 
| -    if (input) { | 
| -      Array<UserKey> keys; | 
| -      Array<UserValue> values; | 
| - | 
| -      // 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 (!internal::Deserialize<Array<Key>>(input->keys.ptr, &keys, context)) | 
| -        success = false; | 
| -      if (!internal::Deserialize<Array<Value>>(input->values.ptr, &values, | 
| -                                               context)) { | 
| -        success = false; | 
| -      } | 
| +    if (!input) | 
| +      return CallSetToNullIfExists<Traits>(output); | 
|  | 
| -      *output = UserType(std::move(keys), std::move(values)); | 
| -    } else { | 
| -      *output = nullptr; | 
| +    Array<UserKey> keys; | 
| +    Array<UserValue> values; | 
| + | 
| +    if (!KeyArraySerializer::DeserializeElements(input->keys.ptr, &keys, | 
| +                                                 context) || | 
| +        !ValueArraySerializer::DeserializeElements(input->values.ptr, &values, | 
| +                                                   context)) { | 
| +      return false; | 
| } | 
| -    return success; | 
| + | 
| +    DCHECK_EQ(keys.size(), values.size()); | 
| +    size_t size = keys.size(); | 
| +    Traits::SetToEmpty(output); | 
| + | 
| +    for (size_t i = 0; i < size; ++i) | 
| +      Traits::Insert(*output, std::move(keys[i]), std::move(values[i])); | 
| +    return true; | 
| } | 
| }; | 
|  | 
|  |