200 lines
8.3 KiB
C++
200 lines
8.3 KiB
C++
// Copyright (c) 2023, 2024, Oracle and/or its affiliates.
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License, version 2.0,
|
|
// as published by the Free Software Foundation.
|
|
//
|
|
// This program is designed to work with certain software (including
|
|
// but not limited to OpenSSL) that is licensed under separate terms,
|
|
// as designated in a particular file or component or in included license
|
|
// documentation. The authors of MySQL hereby grant you an additional
|
|
// permission to link the program and your derivative works with the
|
|
// separately licensed software that they have either included with
|
|
// the program or referenced in the documentation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License, version 2.0, for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
/// @file
|
|
/// Experimental API header
|
|
|
|
#include <iostream>
|
|
|
|
namespace mysql::serialization {
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Field_type, Field_size field_size_defined>
|
|
void Serializer<Serializer_derived_type, Archive_type>::encode_field(
|
|
Level_type level, Field_id_type field_id,
|
|
const Field_definition<Field_type, field_size_defined> &field_definition) {
|
|
get_derived()->encode(level, field_id, field_definition);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Field_type, Field_size field_size_defined>
|
|
void Serializer<Serializer_derived_type, Archive_type>::decode_field(
|
|
Level_type level, Field_id_type field_id, std::size_t serializable_end_pos,
|
|
Field_definition<Field_type, field_size_defined> &field_definition) {
|
|
get_derived()->decode(level, field_id, serializable_end_pos,
|
|
field_definition);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Field_type, Field_size field_size_defined>
|
|
std::size_t
|
|
Serializer<Serializer_derived_type, Archive_type>::get_size_field_def(
|
|
Field_id_type field_id,
|
|
const Field_definition<Field_type, field_size_defined> &field_definition) {
|
|
return Serializer_derived_type::get_size_field_def(field_id,
|
|
field_definition);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Serializable_concrete_type>
|
|
std::size_t
|
|
Serializer<Serializer_derived_type, Archive_type>::get_size_serializable(
|
|
Field_id_type field_id, const Serializable_concrete_type &serializable,
|
|
bool skip_id) {
|
|
return Serializer_derived_type::get_size_serializable(field_id, serializable,
|
|
skip_id);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <typename T>
|
|
std::size_t Serializer<Serializer_derived_type, Archive_type>::get_size(
|
|
const T &arg) {
|
|
return get_size_serializable(0, arg, false);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <typename T>
|
|
Serializer<Serializer_derived_type, Archive_type> &
|
|
Serializer<Serializer_derived_type, Archive_type>::operator<<(const T &arg) {
|
|
Field_id_type field_id = serialization_format_version;
|
|
encode_serializable(m_level, field_id, arg, false);
|
|
return *this;
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <typename T>
|
|
Serializer<Serializer_derived_type, Archive_type>
|
|
&Serializer<Serializer_derived_type, Archive_type>::operator>>(T &arg) {
|
|
Field_id_type field_id = serialization_format_version;
|
|
// passing 0 as serializable_end_pos
|
|
decode_serializable(m_level, field_id, 0, arg, false);
|
|
return *this;
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
Archive_type &Serializer<Serializer_derived_type, Archive_type>::get_archive() {
|
|
return m_archive;
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Serializable_type>
|
|
void Serializer<Serializer_derived_type, Archive_type>::
|
|
encode_serializable_fields(const Serializable_type &serializable,
|
|
Level_type level) {
|
|
auto process_serializable =
|
|
[ this, level ](const auto &field, auto field_id) -> auto{
|
|
this->encode_serializable(level, field_id, field, false);
|
|
};
|
|
auto process_field =
|
|
[ this, level ](const auto &field, auto field_id) -> auto{
|
|
this->encode_field(level, field_id, field);
|
|
++field_id;
|
|
};
|
|
serializable.do_for_each_field(process_serializable, process_field);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Serializable_type>
|
|
void Serializer<Serializer_derived_type, Archive_type>::encode_serializable(
|
|
Level_type level, Field_id_type field_id,
|
|
const Serializable_type &serializable, bool skip_id) {
|
|
if (is_good()) {
|
|
get_derived()->encode_serializable_metadata(level, field_id, serializable,
|
|
skip_id);
|
|
if (is_error()) {
|
|
return;
|
|
}
|
|
// restart numbering below for nested type
|
|
// separate enumeration is needed to keep forward compatibility of
|
|
// serialized types, this way if a field is added inside a nested type,
|
|
// it does not affect rest of the class fields ids (they keep the same
|
|
// numbering). Before restarting, serializable must save it's own id
|
|
encode_serializable_fields(serializable, level + 1);
|
|
}
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Serializable_type>
|
|
void Serializer<Serializer_derived_type, Archive_type>::
|
|
decode_serializable_fields(Serializable_type &serializable,
|
|
Level_type level,
|
|
std::size_t serializable_end_pos) {
|
|
auto process_serializable =
|
|
[ this, level, serializable_end_pos ](auto &field, auto field_id) -> auto{
|
|
this->decode_serializable(level, field_id, serializable_end_pos, field,
|
|
false);
|
|
};
|
|
auto process_field =
|
|
[ this, level, serializable_end_pos ](auto &field, auto field_id) -> auto{
|
|
this->decode_field(level, field_id, serializable_end_pos, field);
|
|
|
|
++field_id;
|
|
};
|
|
serializable.do_for_each_field(process_serializable, process_field);
|
|
}
|
|
|
|
template <class Serializer_derived_type, class Archive_type>
|
|
template <class Serializable_type>
|
|
void Serializer<Serializer_derived_type, Archive_type>::decode_serializable(
|
|
Level_type level, Field_id_type field_id, std::size_t serializable_end_pos,
|
|
Serializable_type &serializable, bool skip_id) {
|
|
// serializable_end_pos = 0 is a marker for serializers that don't check end
|
|
// position and for the top-level serializable field (no parent serializable
|
|
// with end position defined)
|
|
if (skip_id == false && serializable_end_pos != 0 &&
|
|
m_archive.get_read_pos() == serializable_end_pos) { // reached the end
|
|
// missing field handling here
|
|
// must run field missing functors for all serializable fields recursively
|
|
auto run_field_missing_functor = [](auto &field, auto) {
|
|
field.run_field_missing();
|
|
};
|
|
auto serializable_field_missing_functor = [](auto &, auto) {};
|
|
serializable.do_for_each_field(serializable_field_missing_functor,
|
|
run_field_missing_functor);
|
|
return;
|
|
}
|
|
|
|
if (is_good()) {
|
|
auto curr_pos = m_archive.get_read_pos();
|
|
auto encoded_size_read = get_derived()->decode_serializable_metadata(
|
|
level, field_id, serializable, skip_id);
|
|
if (is_error()) {
|
|
return;
|
|
}
|
|
// restart numbering below for nested type
|
|
// separate enumeration is needed to keep forward compatibility of
|
|
// serialized types, this way if a field is added inside a nested type,
|
|
// it does not affect rest of the class fields ids (they keep the same
|
|
// numbering). Before restarting, serializable must save it's own id
|
|
decode_serializable_fields(serializable, level + 1,
|
|
curr_pos + encoded_size_read);
|
|
|
|
auto next_pos = m_archive.get_read_pos();
|
|
auto expected_pos = curr_pos + encoded_size_read;
|
|
if (expected_pos > next_pos && is_good()) {
|
|
m_archive.seek_to(expected_pos - next_pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace mysql::serialization
|