// 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_MAP_SERIALIZATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_
#include <type_traits>
#include <vector>
#include "mojo/public/cpp/bindings/array_data_view.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_data_view.h"
namespace mojo {
namespace internal {
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;
using MaybeConstIterator = typename Base::MaybeConstIterator;
explicit MapKeyReader(MaybeConstUserType& input) : Base(input) {}
~MapKeyReader() {}
using GetNextResult =
decltype(Traits::GetKey(std::declval<MaybeConstIterator&>()));
GetNextResult GetNext() {
GetNextResult 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<MapDataView<Key, Value>, MaybeConstUserType> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = MapTraits<UserType>;
using UserKey = typename Traits::Key;
using UserValue = typename Traits::Value;
using Data = typename MojomTypeTraits<MapDataView<Key, Value>>::Data;
using KeyArraySerializer = ArraySerializer<ArrayDataView<Key>,
std::vector<UserKey>,
MapKeyReader<MaybeConstUserType>>;
using ValueArraySerializer =
ArraySerializer<ArrayDataView<Value>,
std::vector<UserValue>,
MapValueReader<MaybeConstUserType>>;
static void Serialize(MaybeConstUserType& input,
Buffer* buf,
typename Data::BufferWriter* writer,
const ContainerValidateParams* validate_params,
SerializationContext* context) {
DCHECK(validate_params->key_validate_params);
DCHECK(validate_params->element_validate_params);
if (CallIsNullIfExists<Traits>(input))
return;
writer->Allocate(buf);
typename MojomTypeTraits<ArrayDataView<Key>>::Data::BufferWriter
keys_writer;
keys_writer.Allocate(Traits::GetSize(input), buf);
MapKeyReader<MaybeConstUserType> key_reader(input);
KeyArraySerializer::SerializeElements(&key_reader, buf, &keys_writer,
validate_params->key_validate_params,
context);
(*writer)->keys.Set(keys_writer.data());
typename MojomTypeTraits<ArrayDataView<Value>>::Data::BufferWriter
values_writer;
values_writer.Allocate(Traits::GetSize(input), buf);
MapValueReader<MaybeConstUserType> value_reader(input);
ValueArraySerializer::SerializeElements(
&value_reader, buf, &values_writer,
validate_params->element_validate_params, context);
(*writer)->values.Set(values_writer.data());
}
static bool Deserialize(Data* input,
UserType* output,
SerializationContext* context) {
if (!input)
return CallSetToNullIfExists<Traits>(output);
std::vector<UserKey> keys;
std::vector<UserValue> values;
if (!KeyArraySerializer::DeserializeElements(input->keys.Get(), &keys,
context) ||
!ValueArraySerializer::DeserializeElements(input->values.Get(), &values,
context)) {
return false;
}
DCHECK_EQ(keys.size(), values.size());
size_t size = keys.size();
Traits::SetToEmpty(output);
for (size_t i = 0; i < size; ++i) {
if (!Traits::Insert(*output, std::move(keys[i]), std::move(values[i])))
return false;
}
return true;
}
};
} // namespace internal
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MAP_SERIALIZATION_H_