mysql-server/libs/mysql/serialization/serializer_impl.hpp
2025-03-05 14:31:37 +07:00

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