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_data_view.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_data_view.h"
16 
17 namespace mojo {
18 namespace internal {
19 
20 template <typename MaybeConstUserType>
21 class 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 
MapReaderBase(MaybeConstUserType & input)28   explicit MapReaderBase(MaybeConstUserType& input)
29       : input_(input), iter_(Traits::GetBegin(input_)) {}
~MapReaderBase()30   ~MapReaderBase() {}
31 
GetSize()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.
GetDataIfExists()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.
44 template <typename MaybeConstUserType>
45 class MapKeyReader : public MapReaderBase<MaybeConstUserType> {
46  public:
47   using Base = MapReaderBase<MaybeConstUserType>;
48   using Traits = typename Base::Traits;
49   using MaybeConstIterator = typename Base::MaybeConstIterator;
50 
MapKeyReader(MaybeConstUserType & input)51   explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
~MapKeyReader()52   ~MapKeyReader() {}
53 
54   using GetNextResult =
55       decltype(Traits::GetKey(std::declval<MaybeConstIterator&>()));
GetNext()56   GetNextResult GetNext() {
57     GetNextResult key = Traits::GetKey(this->iter_);
58     Traits::AdvanceIterator(this->iter_);
59     return key;
60   }
61 };
62 
63 // Used as the UserTypeReader template parameter of ArraySerializer.
64 template <typename MaybeConstUserType>
65 class MapValueReader : public MapReaderBase<MaybeConstUserType> {
66  public:
67   using Base = MapReaderBase<MaybeConstUserType>;
68   using Traits = typename Base::Traits;
69   using MaybeConstIterator = typename Base::MaybeConstIterator;
70 
MapValueReader(MaybeConstUserType & input)71   explicit MapValueReader(MaybeConstUserType& input) : Base(input) {}
~MapValueReader()72   ~MapValueReader() {}
73 
74   using GetNextResult =
75       decltype(Traits::GetValue(std::declval<MaybeConstIterator&>()));
GetNext()76   GetNextResult GetNext() {
77     GetNextResult value = Traits::GetValue(this->iter_);
78     Traits::AdvanceIterator(this->iter_);
79     return value;
80   }
81 };
82 
83 template <typename Key, typename Value, typename MaybeConstUserType>
84 struct Serializer<MapDataView<Key, Value>, MaybeConstUserType> {
85   using UserType = typename std::remove_const<MaybeConstUserType>::type;
86   using Traits = MapTraits<UserType>;
87   using UserKey = typename Traits::Key;
88   using UserValue = typename Traits::Value;
89   using Data = typename MojomTypeTraits<MapDataView<Key, Value>>::Data;
90   using KeyArraySerializer = ArraySerializer<ArrayDataView<Key>,
91                                              std::vector<UserKey>,
92                                              MapKeyReader<MaybeConstUserType>>;
93   using ValueArraySerializer =
94       ArraySerializer<ArrayDataView<Value>,
95                       std::vector<UserValue>,
96                       MapValueReader<MaybeConstUserType>>;
97 
98   static size_t PrepareToSerialize(MaybeConstUserType& input,
99                                    SerializationContext* context) {
100     if (CallIsNullIfExists<Traits>(input))
101       return 0;
102 
103     size_t struct_overhead = sizeof(Data);
104     MapKeyReader<MaybeConstUserType> key_reader(input);
105     size_t keys_size =
106         KeyArraySerializer::GetSerializedSize(&key_reader, context);
107     MapValueReader<MaybeConstUserType> value_reader(input);
108     size_t values_size =
109         ValueArraySerializer::GetSerializedSize(&value_reader, context);
110 
111     return struct_overhead + keys_size + values_size;
112   }
113 
114   static void Serialize(MaybeConstUserType& input,
115                         Buffer* buf,
116                         Data** output,
117                         const ContainerValidateParams* validate_params,
118                         SerializationContext* context) {
119     DCHECK(validate_params->key_validate_params);
120     DCHECK(validate_params->element_validate_params);
121     if (CallIsNullIfExists<Traits>(input)) {
122       *output = nullptr;
123       return;
124     }
125 
126     auto result = Data::New(buf);
127     if (result) {
128       auto keys_ptr = MojomTypeTraits<ArrayDataView<Key>>::Data::New(
129           Traits::GetSize(input), buf);
130       if (keys_ptr) {
131         MapKeyReader<MaybeConstUserType> key_reader(input);
132         KeyArraySerializer::SerializeElements(
133             &key_reader, buf, keys_ptr, validate_params->key_validate_params,
134             context);
135         result->keys.Set(keys_ptr);
136       }
137 
138       auto values_ptr = MojomTypeTraits<ArrayDataView<Value>>::Data::New(
139           Traits::GetSize(input), buf);
140       if (values_ptr) {
141         MapValueReader<MaybeConstUserType> value_reader(input);
142         ValueArraySerializer::SerializeElements(
143             &value_reader, buf, values_ptr,
144             validate_params->element_validate_params, context);
145         result->values.Set(values_ptr);
146       }
147     }
148     *output = result;
149   }
150 
151   static bool Deserialize(Data* input,
152                           UserType* output,
153                           SerializationContext* context) {
154     if (!input)
155       return CallSetToNullIfExists<Traits>(output);
156 
157     std::vector<UserKey> keys;
158     std::vector<UserValue> values;
159 
160     if (!KeyArraySerializer::DeserializeElements(input->keys.Get(), &keys,
161                                                  context) ||
162         !ValueArraySerializer::DeserializeElements(input->values.Get(), &values,
163                                                    context)) {
164       return false;
165     }
166 
167     DCHECK_EQ(keys.size(), values.size());
168     size_t size = keys.size();
169     Traits::SetToEmpty(output);
170 
171     for (size_t i = 0; i < size; ++i) {
172       if (!Traits::Insert(*output, std::move(keys[i]), std::move(values[i])))
173         return false;
174     }
175     return true;
176   }
177 };
178 
179 }  // namespace internal
180 }  // namespace mojo
181 
182 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
183