| 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;
 | 
|    }
 | 
|  };
 | 
|  
 | 
| 
 |