1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
6#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
7
8#include <type_traits>
9#include <vector>
10
11#include "mojo/public/cpp/bindings/array.h"
12#include "mojo/public/cpp/bindings/lib/array_serialization.h"
13#include "mojo/public/cpp/bindings/lib/map_data_internal.h"
14#include "mojo/public/cpp/bindings/lib/serialization_forward.h"
15#include "mojo/public/cpp/bindings/map.h"
16
17namespace mojo {
18namespace internal {
19
20template <typename MaybeConstUserType>
21class MapReaderBase {
22 public:
23  using UserType = typename std::remove_const<MaybeConstUserType>::type;
24  using Traits = MapTraits<UserType>;
25  using MaybeConstIterator =
26      decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>()));
27
28  explicit MapReaderBase(MaybeConstUserType& input)
29      : input_(input), iter_(Traits::GetBegin(input_)) {}
30  ~MapReaderBase() {}
31
32  size_t GetSize() const { return Traits::GetSize(input_); }
33
34  // Return null because key or value elements are not stored continuously in
35  // memory.
36  void* GetDataIfExists() { return nullptr; }
37
38 protected:
39  MaybeConstUserType& input_;
40  MaybeConstIterator iter_;
41};
42
43// Used as the UserTypeReader template parameter of ArraySerializer.
44template <typename MaybeConstUserType>
45class MapKeyReader : public MapReaderBase<MaybeConstUserType> {
46 public:
47  using Base = MapReaderBase<MaybeConstUserType>;
48  using Traits = typename Base::Traits;
49
50  explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
51  ~MapKeyReader() {}
52
53  const typename Traits::Key& GetNext() {
54    const typename Traits::Key& key = Traits::GetKey(this->iter_);
55    Traits::AdvanceIterator(this->iter_);
56    return key;
57  }
58};
59
60// Used as the UserTypeReader template parameter of ArraySerializer.
61template <typename MaybeConstUserType>
62class MapValueReader : public MapReaderBase<MaybeConstUserType> {
63 public:
64  using Base = MapReaderBase<MaybeConstUserType>;
65  using Traits = typename Base::Traits;
66  using MaybeConstIterator = typename Base::MaybeConstIterator;
67
68  explicit MapValueReader(MaybeConstUserType& input) : Base(input) {}
69  ~MapValueReader() {}
70
71  using GetNextResult =
72      decltype(Traits::GetValue(std::declval<MaybeConstIterator&>()));
73  GetNextResult GetNext() {
74    GetNextResult value = Traits::GetValue(this->iter_);
75    Traits::AdvanceIterator(this->iter_);
76    return value;
77  }
78};
79
80template <typename Key, typename Value, typename MaybeConstUserType>
81struct Serializer<Map<Key, Value>, MaybeConstUserType> {
82  using UserType = typename std::remove_const<MaybeConstUserType>::type;
83  using Traits = MapTraits<UserType>;
84  using UserKey = typename Traits::Key;
85  using UserValue = typename Traits::Value;
86  using Data = typename MojomTypeTraits<Map<Key, Value>>::Data;
87  using KeyArraySerializer = ArraySerializer<Array<Key>,
88                                             std::vector<UserKey>,
89                                             MapKeyReader<MaybeConstUserType>>;
90  using ValueArraySerializer =
91      ArraySerializer<Array<Value>,
92                      std::vector<UserValue>,
93                      MapValueReader<MaybeConstUserType>>;
94
95  static size_t PrepareToSerialize(MaybeConstUserType& input,
96                                   SerializationContext* context) {
97    if (CallIsNullIfExists<Traits>(input))
98      return 0;
99
100    size_t struct_overhead = sizeof(Data);
101    MapKeyReader<MaybeConstUserType> key_reader(input);
102    size_t keys_size =
103        KeyArraySerializer::GetSerializedSize(&key_reader, context);
104    MapValueReader<MaybeConstUserType> value_reader(input);
105    size_t values_size =
106        ValueArraySerializer::GetSerializedSize(&value_reader, context);
107
108    return struct_overhead + keys_size + values_size;
109  }
110
111  static void Serialize(MaybeConstUserType& input,
112                        Buffer* buf,
113                        Data** output,
114                        const ContainerValidateParams* validate_params,
115                        SerializationContext* context) {
116    DCHECK(validate_params->key_validate_params);
117    DCHECK(validate_params->element_validate_params);
118    if (CallIsNullIfExists<Traits>(input)) {
119      *output = nullptr;
120      return;
121    }
122
123    auto result = Data::New(buf);
124    if (result) {
125      auto keys_ptr =
126          MojomTypeTraits<Array<Key>>::Data::New(Traits::GetSize(input), buf);
127      if (keys_ptr) {
128        MapKeyReader<MaybeConstUserType> key_reader(input);
129        KeyArraySerializer::SerializeElements(
130            &key_reader, buf, keys_ptr, validate_params->key_validate_params,
131            context);
132        result->keys.Set(keys_ptr);
133      }
134
135      auto values_ptr =
136          MojomTypeTraits<Array<Value>>::Data::New(Traits::GetSize(input), buf);
137      if (values_ptr) {
138        MapValueReader<MaybeConstUserType> value_reader(input);
139        ValueArraySerializer::SerializeElements(
140            &value_reader, buf, values_ptr,
141            validate_params->element_validate_params, context);
142        result->values.Set(values_ptr);
143      }
144    }
145    *output = result;
146  }
147
148  static bool Deserialize(Data* input,
149                          UserType* output,
150                          SerializationContext* context) {
151    if (!input)
152      return CallSetToNullIfExists<Traits>(output);
153
154    std::vector<UserKey> keys;
155    std::vector<UserValue> values;
156
157    if (!KeyArraySerializer::DeserializeElements(input->keys.Get(), &keys,
158                                                 context) ||
159        !ValueArraySerializer::DeserializeElements(input->values.Get(), &values,
160                                                   context)) {
161      return false;
162    }
163
164    DCHECK_EQ(keys.size(), values.size());
165    size_t size = keys.size();
166    Traits::SetToEmpty(output);
167
168    for (size_t i = 0; i < size; ++i) {
169      if (!Traits::Insert(*output, std::move(keys[i]), std::move(values[i])))
170        return false;
171    }
172    return true;
173  }
174};
175
176}  // namespace internal
177}  // namespace mojo
178
179#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
180