mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-15 01:02:17 +00:00
Converted serialization to a trait-based system
This commit is contained in:
7
TODO.txt
7
TODO.txt
@@ -1,8 +1,13 @@
|
||||
Name change
|
||||
Get rid of get_struct_fields
|
||||
Put serialization specializations together with the messages
|
||||
Split serialization tests according to file structure
|
||||
Split impls to impl header
|
||||
Get rid of contexts files
|
||||
Transform tags into an enum
|
||||
serialization_test_common
|
||||
Should be in unit/
|
||||
Should not be header only
|
||||
Should not require including all messages
|
||||
Should have things in namespace test, not detail
|
||||
Split serialization tests into chunks following file structure
|
||||
Try to make string_fixed just an array of chars instead of a value_holder
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_COMMON_MESSAGES_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_COMMON_MESSAGES_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/deserialization_context.hpp"
|
||||
#include "boost/mysql/detail/auxiliar/get_struct_fields.hpp"
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
#include "boost/mysql/detail/protocol/constants.hpp"
|
||||
#include "boost/mysql/collation.hpp"
|
||||
#include "boost/mysql/error.hpp"
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
@@ -103,8 +101,18 @@ struct get_struct_fields<column_definition_packet>
|
||||
);
|
||||
};
|
||||
|
||||
inline errc deserialize(ok_packet& output, deserialization_context& ctx) noexcept;
|
||||
inline errc deserialize(column_definition_packet& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<ok_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline errc deserialize_(ok_packet& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct serialization_traits<column_definition_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline errc deserialize_(column_definition_packet& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
inline error_code process_error_packet(deserialization_context& ctx, error_info& info);
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_HANDSHAKE_MESSAGES_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_HANDSHAKE_MESSAGES_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/serialization_context.hpp"
|
||||
#include "boost/mysql/detail/protocol/deserialization_context.hpp"
|
||||
#include "boost/mysql/detail/protocol/protocol_types.hpp"
|
||||
#include "boost/mysql/detail/auxiliar/get_struct_fields.hpp"
|
||||
#include "boost/mysql/error.hpp"
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
@@ -94,10 +90,24 @@ struct get_struct_fields<auth_switch_response_packet>
|
||||
);
|
||||
};
|
||||
|
||||
inline errc deserialize(handshake_packet& output, deserialization_context& ctx) noexcept;
|
||||
inline std::size_t get_size(const handshake_response_packet& value, const serialization_context& ctx) noexcept;
|
||||
inline void serialize(const handshake_response_packet& value, serialization_context& ctx) noexcept;
|
||||
inline errc deserialize(auth_switch_request_packet& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<handshake_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline errc deserialize_(handshake_packet& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct serialization_traits<handshake_response_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline std::size_t get_size_(const handshake_response_packet& value, const serialization_context& ctx) noexcept;
|
||||
static inline void serialize_(const handshake_response_packet& value, serialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct serialization_traits<auth_switch_request_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline errc deserialize_(auth_switch_request_packet& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_COMMON_MESSAGES_IPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_COMMON_MESSAGES_IPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::ok_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(
|
||||
ok_packet& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -24,7 +26,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
}
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::column_definition_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(
|
||||
column_definition_packet& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_HANDSHAKE_MESSAGES_IPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_HANDSHAKE_MESSAGES_IPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::handshake_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(
|
||||
handshake_packet& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -67,7 +70,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
std::size_t boost::mysql::detail::get_size(
|
||||
std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::handshake_response_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::get_size_(
|
||||
const handshake_response_packet& value,
|
||||
const serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -87,7 +94,11 @@ std::size_t boost::mysql::detail::get_size(
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void boost::mysql::detail::serialize(
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::handshake_response_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::serialize_(
|
||||
const handshake_response_packet& value,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -106,7 +117,11 @@ inline void boost::mysql::detail::serialize(
|
||||
serialize(value.client_plugin_name, ctx);
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::auth_switch_request_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(
|
||||
auth_switch_request_packet& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_PREPARED_STATEMENT_MESSAGES_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_PREPARED_STATEMENT_MESSAGES_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
#include "boost/mysql/detail/protocol/null_bitmap_traits.hpp"
|
||||
|
||||
namespace boost {
|
||||
@@ -88,7 +87,11 @@ inline void serialize_binary_value(
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::com_stmt_prepare_ok_packet,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(
|
||||
com_stmt_prepare_ok_packet& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -105,7 +108,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
}
|
||||
|
||||
template <typename ForwardIterator>
|
||||
inline std::size_t boost::mysql::detail::get_size(
|
||||
inline std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::com_stmt_execute_packet<ForwardIterator>,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::get_size_(
|
||||
const com_stmt_execute_packet<ForwardIterator>& value,
|
||||
const serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -127,7 +134,11 @@ inline std::size_t boost::mysql::detail::get_size(
|
||||
}
|
||||
|
||||
template <typename ForwardIterator>
|
||||
inline void boost::mysql::detail::serialize(
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::com_stmt_execute_packet<ForwardIterator>,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::serialize_(
|
||||
const com_stmt_execute_packet<ForwardIterator>& input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
|
||||
310
include/boost/mysql/detail/protocol/impl/serialization.hpp
Normal file
310
include/boost/mysql/detail/protocol/impl/serialization.hpp
Normal file
@@ -0,0 +1,310 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP_
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr std::size_t get_int_size()
|
||||
{
|
||||
static_assert(is_fixed_size_int<T>());
|
||||
return std::is_same<T, int3>::value ? 3 :
|
||||
std::is_same<T, int6>::value ? 6 : sizeof(T);
|
||||
}
|
||||
|
||||
struct is_command_helper
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr std::true_type get(decltype(T::command_id)*);
|
||||
|
||||
template <typename T>
|
||||
static constexpr std::false_type get(...);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_command : decltype(is_command_helper::get<T>(nullptr))
|
||||
{
|
||||
};
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
errc deserialize_struct(
|
||||
[[maybe_unused]] T& output,
|
||||
[[maybe_unused]] deserialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index == std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
return errc::ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr auto pmem = std::get<index>(fields);
|
||||
errc err = deserialize(output.*pmem, ctx);
|
||||
if (err != errc::ok)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
return deserialize_struct<index+1>(output, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
void serialize_struct(
|
||||
[[maybe_unused]] const T& value,
|
||||
[[maybe_unused]] serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index < std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
auto pmem = std::get<index>(fields);
|
||||
serialize(value.*pmem, ctx);
|
||||
serialize_struct<index+1>(value, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
std::size_t get_size_struct(
|
||||
[[maybe_unused]] const T& input,
|
||||
[[maybe_unused]] const serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index == std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr auto pmem = std::get<index>(fields);
|
||||
return get_size_struct<index+1>(input, ctx) +
|
||||
get_size(input.*pmem, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
template <typename T>
|
||||
constexpr bool boost::mysql::detail::is_fixed_size_int()
|
||||
{
|
||||
return
|
||||
std::is_integral<get_value_type_t<T>>::value &&
|
||||
std::is_base_of<value_holder<get_value_type_t<T>>, T>::value &&
|
||||
!std::is_same<T, int_lenenc>::value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::fixed_size_int_tag
|
||||
>::deserialize_(
|
||||
T& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
static_assert(std::is_standard_layout_v<decltype(T::value)>);
|
||||
|
||||
constexpr auto size = get_int_size<T>();
|
||||
if (!ctx.enough_size(size))
|
||||
{
|
||||
return errc::incomplete_message;
|
||||
}
|
||||
|
||||
memset(&output.value, 0, sizeof(output.value));
|
||||
memcpy(&output.value, ctx.first(), size);
|
||||
boost::endian::little_to_native_inplace(output);
|
||||
ctx.advance(size);
|
||||
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::fixed_size_int_tag
|
||||
>::serialize_(
|
||||
T input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
boost::endian::native_to_little_inplace(input);
|
||||
ctx.write(&input.value, get_int_size<T>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::size_t boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::fixed_size_int_tag
|
||||
>::get_size_(T, const serialization_context&) noexcept
|
||||
{
|
||||
return get_int_size<T>();
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
boost::mysql::errc boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::string_fixed<N>,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
string_fixed<N>& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
if (!ctx.enough_size(N))
|
||||
{
|
||||
return errc::incomplete_message;
|
||||
}
|
||||
memcpy(&output.value, ctx.first(), N);
|
||||
ctx.advance(N);
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::enum_tag
|
||||
>::deserialize_(
|
||||
T& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
serializable_type value;
|
||||
errc err = deserialize(value, ctx);
|
||||
if (err != errc::ok)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
output = static_cast<T>(value.value);
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::enum_tag
|
||||
>::get_size_(T, const serialization_context&) noexcept
|
||||
{
|
||||
return get_int_size<serializable_type>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::floating_point_tag
|
||||
>::deserialize_(T& output, deserialization_context& ctx) noexcept
|
||||
{
|
||||
// Size check
|
||||
if (!ctx.enough_size(sizeof(T))) return errc::incomplete_message;
|
||||
|
||||
// Endianness conversion
|
||||
// Boost.Endian support for floats start at 1.71. TODO: maybe update requirements and CI
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
char buf [sizeof(T)];
|
||||
std::memcpy(buf, ctx.first(), sizeof(T));
|
||||
std::reverse(buf, buf + sizeof(T));
|
||||
std::memcpy(&output, buf, sizeof(T));
|
||||
#else
|
||||
std::memcpy(&output, ctx.first(), sizeof(T));
|
||||
#endif
|
||||
ctx.advance(sizeof(T));
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::floating_point_tag
|
||||
>::serialize_(T input, serialization_context& ctx) noexcept
|
||||
{
|
||||
// Endianness conversion
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
char buf [sizeof(T)];
|
||||
std::memcpy(buf, &input, sizeof(T));
|
||||
std::reverse(buf, buf + sizeof(T));
|
||||
ctx.write(buf, sizeof(T));
|
||||
#else
|
||||
ctx.write(&input, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::deserialize_(T& output, deserialization_context& ctx) noexcept
|
||||
{
|
||||
return deserialize_struct<0>(output, ctx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::serialize_(
|
||||
[[maybe_unused]] const T& input,
|
||||
[[maybe_unused]] serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
// For commands, add the command ID. Commands are only sent by the client,
|
||||
// so this is not considered in the deserialization functions.
|
||||
if constexpr (is_command<T>::value)
|
||||
{
|
||||
serialize(int1(T::command_id), ctx);
|
||||
}
|
||||
serialize_struct<0>(input, ctx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
T,
|
||||
boost::mysql::detail::struct_tag
|
||||
>::get_size_(const T& input, const serialization_context& ctx) noexcept
|
||||
{
|
||||
std::size_t res = is_command<T>::value ? 1 : 0;
|
||||
res += get_size_struct<0>(input, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Serializable, typename Allocator>
|
||||
void boost::mysql::detail::serialize_message(
|
||||
const Serializable& input,
|
||||
capabilities caps,
|
||||
basic_bytestring<Allocator>& buffer
|
||||
)
|
||||
{
|
||||
serialization_context ctx (caps);
|
||||
std::size_t size = get_size(input, ctx);
|
||||
buffer.resize(size);
|
||||
ctx.set_first(buffer.data());
|
||||
serialize(input, ctx);
|
||||
assert(ctx.first() == buffer.data() + buffer.size());
|
||||
}
|
||||
|
||||
template <typename Deserializable>
|
||||
boost::mysql::error_code boost::mysql::detail::deserialize_message(
|
||||
Deserializable& output,
|
||||
deserialization_context& ctx
|
||||
)
|
||||
{
|
||||
auto err = deserialize(output, ctx);
|
||||
if (err != errc::ok) return make_error_code(err);
|
||||
if (!ctx.empty()) return make_error_code(errc::extra_bytes);
|
||||
return error_code();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP_ */
|
||||
@@ -5,6 +5,14 @@ namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
inline std::string_view get_string(
|
||||
const std::uint8_t* from,
|
||||
std::size_t size
|
||||
)
|
||||
{
|
||||
return std::string_view(reinterpret_cast<const char*>(from), size);
|
||||
}
|
||||
|
||||
inline errc deserialize_binary_date(
|
||||
date& output,
|
||||
std::uint8_t length,
|
||||
@@ -110,7 +118,11 @@ struct broken_time
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::int_lenenc,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
int_lenenc& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -148,7 +160,12 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return err;
|
||||
}
|
||||
|
||||
inline void boost::mysql::detail::serialize(
|
||||
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::int_lenenc,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::serialize_(
|
||||
int_lenenc input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -174,9 +191,13 @@ inline void boost::mysql::detail::serialize(
|
||||
}
|
||||
}
|
||||
|
||||
inline std::size_t boost::mysql::detail::get_size(
|
||||
int_lenenc input, const
|
||||
serialization_context&
|
||||
inline std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::int_lenenc,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::get_size_(
|
||||
int_lenenc input,
|
||||
const serialization_context&
|
||||
) noexcept
|
||||
{
|
||||
if (input.value < 251) return 1;
|
||||
@@ -185,7 +206,11 @@ inline std::size_t boost::mysql::detail::get_size(
|
||||
else return 9;
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::string_null,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
string_null& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -200,7 +225,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::string_eof,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
string_eof& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -210,7 +239,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::detail::string_lenenc,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
string_lenenc& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -231,7 +264,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
inline std::size_t boost::mysql::detail::get_size(
|
||||
inline std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::date,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::get_size_(
|
||||
const date&,
|
||||
const serialization_context&
|
||||
) noexcept
|
||||
@@ -240,7 +277,11 @@ inline std::size_t boost::mysql::detail::get_size(
|
||||
return 5; // length, year, month, day
|
||||
}
|
||||
|
||||
inline void boost::mysql::detail::serialize(
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::date,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::serialize_(
|
||||
const date& input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -250,7 +291,11 @@ inline void boost::mysql::detail::serialize(
|
||||
serialize_binary_ymd(::date::year_month_day (input), ctx);
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::date,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
date& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -262,7 +307,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
}
|
||||
|
||||
// datetime
|
||||
inline std::size_t boost::mysql::detail::get_size(
|
||||
inline std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::datetime,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::get_size_(
|
||||
const datetime& input,
|
||||
const serialization_context&
|
||||
) noexcept
|
||||
@@ -271,7 +320,11 @@ inline std::size_t boost::mysql::detail::get_size(
|
||||
return dt.binary_serialized_length() + 1; // extra length prefix byte
|
||||
}
|
||||
|
||||
inline void boost::mysql::detail::serialize(
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::datetime,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::serialize_(
|
||||
const datetime& input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -299,7 +352,11 @@ inline void boost::mysql::detail::serialize(
|
||||
}
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::datetime,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
datetime& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -337,7 +394,11 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
}
|
||||
|
||||
// time
|
||||
inline std::size_t boost::mysql::detail::get_size(
|
||||
inline std::size_t
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::time,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::get_size_(
|
||||
const time& input,
|
||||
const serialization_context&
|
||||
) noexcept
|
||||
@@ -345,7 +406,11 @@ inline std::size_t boost::mysql::detail::get_size(
|
||||
return broken_time(input).binary_serialized_length() + 1; // length byte
|
||||
}
|
||||
|
||||
inline void boost::mysql::detail::serialize(
|
||||
inline void
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::time,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::serialize_(
|
||||
const time& input,
|
||||
serialization_context& ctx
|
||||
) noexcept
|
||||
@@ -372,7 +437,11 @@ inline void boost::mysql::detail::serialize(
|
||||
}
|
||||
}
|
||||
|
||||
inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
inline boost::mysql::errc
|
||||
boost::mysql::detail::serialization_traits<
|
||||
boost::mysql::time,
|
||||
boost::mysql::detail::no_serialization_tag
|
||||
>::deserialize_(
|
||||
time& output,
|
||||
deserialization_context& ctx
|
||||
) noexcept
|
||||
@@ -417,33 +486,6 @@ inline boost::mysql::errc boost::mysql::detail::deserialize(
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename Serializable, typename Allocator>
|
||||
void boost::mysql::detail::serialize_message(
|
||||
const Serializable& input,
|
||||
capabilities caps,
|
||||
basic_bytestring<Allocator>& buffer
|
||||
)
|
||||
{
|
||||
serialization_context ctx (caps);
|
||||
std::size_t size = get_size(input, ctx);
|
||||
buffer.resize(size);
|
||||
ctx.set_first(buffer.data());
|
||||
serialize(input, ctx);
|
||||
assert(ctx.first() == buffer.data() + buffer.size());
|
||||
}
|
||||
|
||||
template <typename Deserializable>
|
||||
boost::mysql::error_code boost::mysql::detail::deserialize_message(
|
||||
Deserializable& output,
|
||||
deserialization_context& ctx
|
||||
)
|
||||
{
|
||||
auto err = deserialize(output, ctx);
|
||||
if (err != errc::ok) return make_error_code(err);
|
||||
if (!ctx.empty()) return make_error_code(errc::extra_bytes);
|
||||
return error_code();
|
||||
}
|
||||
|
||||
inline std::pair<boost::mysql::error_code, std::uint8_t>
|
||||
boost::mysql::detail::deserialize_message_type(
|
||||
deserialization_context& ctx
|
||||
@@ -464,6 +506,4 @@ boost::mysql::detail::deserialize_message_type(
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_IPP_ */
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_PREPARED_STATEMENT_MESSAGES_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_PREPARED_STATEMENT_MESSAGES_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/protocol_types.hpp"
|
||||
#include "boost/mysql/detail/protocol/serialization_context.hpp"
|
||||
#include "boost/mysql/detail/protocol/deserialization_context.hpp"
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
#include "boost/mysql/detail/protocol/constants.hpp"
|
||||
#include "boost/mysql/detail/auxiliar/get_struct_fields.hpp"
|
||||
#include "boost/mysql/value.hpp"
|
||||
#include "boost/mysql/error.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
@@ -107,13 +103,20 @@ struct get_struct_fields<com_stmt_close_packet>
|
||||
);
|
||||
};
|
||||
|
||||
inline errc deserialize(com_stmt_prepare_ok_packet& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<com_stmt_prepare_ok_packet, struct_tag> : noop_serialization_traits
|
||||
{
|
||||
static inline errc deserialize_(com_stmt_prepare_ok_packet& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
template <typename FowardIterator>
|
||||
inline std::size_t get_size(const com_stmt_execute_packet<FowardIterator>& value, const serialization_context& ctx) noexcept;
|
||||
|
||||
template <typename FowardIterator>
|
||||
inline void serialize(const com_stmt_execute_packet<FowardIterator>& input, serialization_context& ctx) noexcept;
|
||||
template <typename ForwardIterator>
|
||||
struct serialization_traits<com_stmt_execute_packet<ForwardIterator>, struct_tag>: noop_serialization_traits
|
||||
{
|
||||
static inline std::size_t get_size_(const com_stmt_execute_packet<ForwardIterator>& value,
|
||||
const serialization_context& ctx) noexcept;
|
||||
static inline void serialize_(const com_stmt_execute_packet<ForwardIterator>& input,
|
||||
serialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // mysql
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_QUERY_MESSAGES_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_QUERY_MESSAGES_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/protocol_types.hpp"
|
||||
#include "boost/mysql/detail/auxiliar/get_struct_fields.hpp"
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
#include <tuple>
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -16,346 +16,200 @@ namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
struct no_serialization_tag {};
|
||||
|
||||
/**
|
||||
* Base forms:
|
||||
* errc deserialize(T& output, deserialization_context&) noexcept
|
||||
* void serialize(const T& input, SerializationContext&) noexcept
|
||||
* std::size_t get_size(const T& input, const SerializationContext&) noexcept
|
||||
*/
|
||||
template <typename T>
|
||||
struct get_serialization_tag;
|
||||
|
||||
template <typename T, typename Tag=typename get_serialization_tag<T>::type>
|
||||
struct serialization_traits;
|
||||
|
||||
template <typename T>
|
||||
errc deserialize(T& output, deserialization_context& ctx) noexcept
|
||||
{
|
||||
return serialization_traits<T>::deserialize_(output, ctx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void serialize(const T& input, serialization_context& ctx) noexcept
|
||||
{
|
||||
serialization_traits<T>::serialize_(input, ctx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t get_size(const T& input, const serialization_context& ctx) noexcept
|
||||
{
|
||||
return serialization_traits<T>::get_size_(input, ctx);
|
||||
}
|
||||
|
||||
// Fixed-size integers
|
||||
struct fixed_size_int_tag {};
|
||||
|
||||
template <typename T>
|
||||
struct is_fixed_size_int
|
||||
constexpr bool is_fixed_size_int();
|
||||
|
||||
template <typename T>
|
||||
struct serialization_traits<T, fixed_size_int_tag>
|
||||
{
|
||||
static constexpr bool value =
|
||||
std::is_integral<get_value_type_t<T>>::value &&
|
||||
std::is_base_of<value_holder<get_value_type_t<T>>, T>::value;
|
||||
static errc deserialize_(T& output, deserialization_context& ctx) noexcept;
|
||||
static void serialize_(T input, serialization_context& ctx) noexcept;
|
||||
static constexpr std::size_t get_size_(T, const serialization_context&) noexcept;
|
||||
};
|
||||
|
||||
template <> struct is_fixed_size_int<int_lenenc> : std::false_type {};
|
||||
|
||||
template <typename T> constexpr bool is_fixed_size_v = is_fixed_size_int<T>::value;
|
||||
|
||||
template <typename T>
|
||||
struct get_int_size
|
||||
{
|
||||
static_assert(is_fixed_size_v<T>);
|
||||
static constexpr std::size_t value = sizeof(T::value);
|
||||
};
|
||||
|
||||
template <> struct get_int_size<int3> { static constexpr std::size_t value = 3; };
|
||||
template <> struct get_int_size<int6> { static constexpr std::size_t value = 6; };
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_fixed_size_int<T>::value, errc>
|
||||
deserialize(T& output, deserialization_context& ctx) noexcept
|
||||
{
|
||||
static_assert(std::is_standard_layout_v<decltype(T::value)>);
|
||||
|
||||
constexpr auto size = get_int_size<T>::value;
|
||||
if (!ctx.enough_size(size))
|
||||
{
|
||||
return errc::incomplete_message;
|
||||
}
|
||||
|
||||
memset(&output.value, 0, sizeof(output.value));
|
||||
memcpy(&output.value, ctx.first(), size);
|
||||
boost::endian::little_to_native_inplace(output);
|
||||
ctx.advance(size);
|
||||
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_fixed_size_v<T>>
|
||||
serialize(T input, serialization_context& ctx) noexcept
|
||||
{
|
||||
boost::endian::native_to_little_inplace(input);
|
||||
ctx.write(&input.value, get_int_size<T>::value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::enable_if_t<is_fixed_size_v<T>, std::size_t>
|
||||
get_size(T, const serialization_context&) noexcept
|
||||
{
|
||||
return get_int_size<T>::value;
|
||||
}
|
||||
|
||||
// int_lenenc
|
||||
inline errc deserialize(int_lenenc& output, deserialization_context& ctx) noexcept;
|
||||
inline void serialize(int_lenenc input, serialization_context& ctx) noexcept;
|
||||
inline std::size_t get_size(int_lenenc input, const serialization_context&) noexcept;
|
||||
|
||||
// Helper for strings
|
||||
inline std::string_view get_string(const std::uint8_t* from, std::size_t size)
|
||||
template <>
|
||||
struct serialization_traits<int_lenenc, no_serialization_tag>
|
||||
{
|
||||
return std::string_view (reinterpret_cast<const char*>(from), size);
|
||||
}
|
||||
static inline errc deserialize_(int_lenenc& output, deserialization_context& ctx) noexcept;
|
||||
static inline void serialize_(int_lenenc input, serialization_context& ctx) noexcept;
|
||||
static inline std::size_t get_size_(int_lenenc input, const serialization_context&) noexcept;
|
||||
};
|
||||
|
||||
|
||||
// string_fixed
|
||||
template <std::size_t N>
|
||||
errc deserialize(string_fixed<N>& output, deserialization_context& ctx) noexcept
|
||||
struct serialization_traits<string_fixed<N>, no_serialization_tag>
|
||||
{
|
||||
if (!ctx.enough_size(N))
|
||||
static errc deserialize_(string_fixed<N>& output, deserialization_context& ctx) noexcept;
|
||||
static void serialize_(const string_fixed<N>& input, serialization_context& ctx) noexcept
|
||||
{
|
||||
return errc::incomplete_message;
|
||||
ctx.write(input.value.data(), N);
|
||||
}
|
||||
memcpy(&output.value, ctx.first(), N);
|
||||
ctx.advance(N);
|
||||
return errc::ok;
|
||||
}
|
||||
static constexpr std::size_t get_size_(const string_fixed<N>&, const serialization_context&) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
void serialize(const string_fixed<N>& input, serialization_context& ctx) noexcept
|
||||
{
|
||||
ctx.write(input.value.data(), N);
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr std::size_t get_size(const string_fixed<N>&, const serialization_context&) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
// string_null
|
||||
inline errc deserialize(string_null& output, deserialization_context& ctx) noexcept;
|
||||
inline void serialize(string_null input, serialization_context& ctx) noexcept
|
||||
template <>
|
||||
struct serialization_traits<string_null, no_serialization_tag>
|
||||
{
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
ctx.write(0); // null terminator
|
||||
}
|
||||
inline std::size_t get_size(string_null input, const serialization_context&) noexcept
|
||||
{
|
||||
return input.value.size() + 1;
|
||||
}
|
||||
static inline errc deserialize_(string_null& output, deserialization_context& ctx) noexcept;
|
||||
static inline void serialize_(string_null input, serialization_context& ctx) noexcept
|
||||
{
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
ctx.write(0); // null terminator
|
||||
}
|
||||
static inline std::size_t get_size_(string_null input, const serialization_context&) noexcept
|
||||
{
|
||||
return input.value.size() + 1;
|
||||
}
|
||||
};
|
||||
|
||||
// string_eof
|
||||
inline errc deserialize(string_eof& output, deserialization_context& ctx) noexcept;
|
||||
inline void serialize(string_eof input, serialization_context& ctx) noexcept
|
||||
template <>
|
||||
struct serialization_traits<string_eof, no_serialization_tag>
|
||||
{
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
}
|
||||
inline std::size_t get_size(string_eof input, const serialization_context&) noexcept
|
||||
{
|
||||
return input.value.size();
|
||||
}
|
||||
static inline errc deserialize_(string_eof& output, deserialization_context& ctx) noexcept;
|
||||
static inline void serialize_(string_eof input, serialization_context& ctx) noexcept
|
||||
{
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
}
|
||||
static inline std::size_t get_size_(string_eof input, const serialization_context&) noexcept
|
||||
{
|
||||
return input.value.size();
|
||||
}
|
||||
};
|
||||
|
||||
// string_lenenc
|
||||
inline errc deserialize(string_lenenc& output, deserialization_context& ctx) noexcept;
|
||||
inline void serialize(string_lenenc input, serialization_context& ctx) noexcept
|
||||
template <>
|
||||
struct serialization_traits<string_lenenc, no_serialization_tag>
|
||||
{
|
||||
serialize(int_lenenc(input.value.size()), ctx);
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
}
|
||||
inline std::size_t get_size(string_lenenc input, const serialization_context& ctx) noexcept
|
||||
{
|
||||
return get_size(int_lenenc(input.value.size()), ctx) + input.value.size();
|
||||
}
|
||||
static inline errc deserialize_(string_lenenc& output, deserialization_context& ctx) noexcept;
|
||||
static inline void serialize_(string_lenenc input, serialization_context& ctx) noexcept
|
||||
{
|
||||
serialize(int_lenenc(input.value.size()), ctx);
|
||||
ctx.write(input.value.data(), input.value.size());
|
||||
}
|
||||
static inline std::size_t get_size_(string_lenenc input, const serialization_context& ctx) noexcept
|
||||
{
|
||||
return get_size(int_lenenc(input.value.size()), ctx) + input.value.size();
|
||||
}
|
||||
};
|
||||
|
||||
// Enums
|
||||
template <typename T, typename=std::enable_if_t<std::is_enum_v<T>>>
|
||||
errc deserialize(T& output, deserialization_context& ctx) noexcept
|
||||
struct enum_tag {};
|
||||
|
||||
template <typename T>
|
||||
struct serialization_traits<T, enum_tag>
|
||||
{
|
||||
value_holder<std::underlying_type_t<T>> value;
|
||||
errc err = deserialize(value, ctx);
|
||||
if (err != errc::ok)
|
||||
using underlying_type = std::underlying_type_t<T>;
|
||||
using serializable_type = value_holder<underlying_type>;
|
||||
|
||||
static errc deserialize_(T& output, deserialization_context& ctx) noexcept;
|
||||
static void serialize_(T input, serialization_context& ctx) noexcept
|
||||
{
|
||||
return err;
|
||||
serialize(serializable_type(static_cast<underlying_type>(input)), ctx);
|
||||
}
|
||||
output = static_cast<T>(value.value);
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T, typename=std::enable_if_t<std::is_enum_v<T>>>
|
||||
void serialize(T input, serialization_context& ctx) noexcept
|
||||
{
|
||||
value_holder<std::underlying_type_t<T>> value {static_cast<std::underlying_type_t<T>>(input)};
|
||||
serialize(value, ctx);
|
||||
}
|
||||
|
||||
template <typename T, typename=std::enable_if_t<std::is_enum_v<T>>>
|
||||
std::size_t get_size(T, const serialization_context&) noexcept
|
||||
{
|
||||
return get_int_size<value_holder<std::underlying_type_t<T>>>::value;
|
||||
}
|
||||
static std::size_t get_size_(T, const serialization_context&) noexcept;
|
||||
};
|
||||
|
||||
// Floating points
|
||||
static_assert(std::numeric_limits<float>::is_iec559);
|
||||
static_assert(std::numeric_limits<double>::is_iec559);
|
||||
struct floating_point_tag {};
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>, errc>
|
||||
deserialize(T& output, deserialization_context& ctx) noexcept
|
||||
struct serialization_traits<T, floating_point_tag>
|
||||
{
|
||||
// Size check
|
||||
if (!ctx.enough_size(sizeof(T))) return errc::incomplete_message;
|
||||
static_assert(std::numeric_limits<T>::is_iec559);
|
||||
static errc deserialize_(T& output, deserialization_context& ctx) noexcept;
|
||||
static void serialize_(T input, serialization_context& ctx) noexcept;
|
||||
static std::size_t get_size_(T, const serialization_context&) noexcept
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
// Endianness conversion
|
||||
// Boost.Endian support for floats start at 1.71. TODO: maybe update requirements and CI
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
char buf [sizeof(T)];
|
||||
std::memcpy(buf, ctx.first(), sizeof(T));
|
||||
std::reverse(buf, buf + sizeof(T));
|
||||
std::memcpy(&output, buf, sizeof(T));
|
||||
#else
|
||||
std::memcpy(&output, ctx.first(), sizeof(T));
|
||||
#endif
|
||||
ctx.advance(sizeof(T));
|
||||
return errc::ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>>
|
||||
serialize(T input, serialization_context& ctx) noexcept
|
||||
{
|
||||
// Endianness conversion
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
char buf [sizeof(T)];
|
||||
std::memcpy(buf, &input, sizeof(T));
|
||||
std::reverse(buf, buf + sizeof(T));
|
||||
ctx.write(buf, sizeof(T));
|
||||
#else
|
||||
ctx.write(&input, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_floating_point_v<T>, std::size_t>
|
||||
get_size(T, const serialization_context&) noexcept
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
// Dates and times
|
||||
inline std::size_t get_size(const date& input, const serialization_context& ctx) noexcept;
|
||||
inline void serialize(const date& input, serialization_context& ctx) noexcept;
|
||||
inline errc deserialize(date& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<date, no_serialization_tag>
|
||||
{
|
||||
static inline std::size_t get_size_(const date& input, const serialization_context& ctx) noexcept;
|
||||
static inline void serialize_(const date& input, serialization_context& ctx) noexcept;
|
||||
static inline errc deserialize_(date& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
inline std::size_t get_size(const datetime& input, const serialization_context& ctx) noexcept;
|
||||
inline void serialize(const datetime& input, serialization_context& ctx) noexcept;
|
||||
inline errc deserialize(datetime& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<datetime, no_serialization_tag>
|
||||
{
|
||||
static inline std::size_t get_size_(const datetime& input, const serialization_context& ctx) noexcept;
|
||||
static inline void serialize_(const datetime& input, serialization_context& ctx) noexcept;
|
||||
static inline errc deserialize_(datetime& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
inline std::size_t get_size(const time& input, const serialization_context& ctx) noexcept;
|
||||
inline void serialize(const time& input, serialization_context& ctx) noexcept;
|
||||
inline errc deserialize(time& output, deserialization_context& ctx) noexcept;
|
||||
template <>
|
||||
struct serialization_traits<time, no_serialization_tag>
|
||||
{
|
||||
static inline std::size_t get_size_(const time& input, const serialization_context& ctx) noexcept;
|
||||
static inline void serialize_(const time& input, serialization_context& ctx) noexcept;
|
||||
static inline errc deserialize_(time& output, deserialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
// Structs and commands (messages)
|
||||
struct struct_tag {};
|
||||
|
||||
template <typename T>
|
||||
struct is_struct_with_fields
|
||||
constexpr bool is_struct_with_fields()
|
||||
{
|
||||
static constexpr bool value = !std::is_same_v<
|
||||
return !std::is_same_v<
|
||||
std::decay_t<decltype(get_struct_fields<T>::value)>,
|
||||
not_a_struct_with_fields
|
||||
>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct serialization_traits<T, struct_tag>
|
||||
{
|
||||
static errc deserialize_(T& output, deserialization_context& ctx) noexcept;
|
||||
static void serialize_(const T& input, serialization_context& ctx) noexcept;
|
||||
static std::size_t get_size_(const T& input, const serialization_context& ctx) noexcept;
|
||||
};
|
||||
|
||||
struct is_command_helper
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr std::true_type get(decltype(T::command_id)*);
|
||||
|
||||
template <typename T>
|
||||
static constexpr std::false_type get(...);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_command : decltype(is_command_helper::get<T>(nullptr))
|
||||
{
|
||||
};
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
errc deserialize_struct(
|
||||
[[maybe_unused]] T& output,
|
||||
[[maybe_unused]] deserialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index == std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
return errc::ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr auto pmem = std::get<index>(fields);
|
||||
errc err = deserialize(output.*pmem, ctx);
|
||||
if (err != errc::ok)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
return deserialize_struct<index+1>(output, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_struct_with_fields<T>::value, errc>
|
||||
deserialize(T& output, deserialization_context& ctx) noexcept
|
||||
{
|
||||
return deserialize_struct<0>(output, ctx);
|
||||
}
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
void serialize_struct(
|
||||
[[maybe_unused]] const T& value,
|
||||
[[maybe_unused]] serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index < std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
auto pmem = std::get<index>(fields);
|
||||
serialize(value.*pmem, ctx);
|
||||
serialize_struct<index+1>(value, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_struct_with_fields<T>::value>
|
||||
serialize(
|
||||
[[maybe_unused]] const T& input,
|
||||
[[maybe_unused]] serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
// For commands, add the command ID. Commands are only sent by the client,
|
||||
// so this is not considered in the deserialization functions.
|
||||
if constexpr (is_command<T>::value)
|
||||
{
|
||||
serialize(int1(T::command_id), ctx);
|
||||
}
|
||||
serialize_struct<0>(input, ctx);
|
||||
}
|
||||
|
||||
template <std::size_t index, typename T>
|
||||
std::size_t get_size_struct(
|
||||
[[maybe_unused]] const T& input,
|
||||
[[maybe_unused]] const serialization_context& ctx
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto fields = get_struct_fields<T>::value;
|
||||
if constexpr (index == std::tuple_size<decltype(fields)>::value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr auto pmem = std::get<index>(fields);
|
||||
return get_size_struct<index+1>(input, ctx) +
|
||||
get_size(input.*pmem, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_struct_with_fields<T>::value, std::size_t>
|
||||
get_size(const T& input, const serialization_context& ctx) noexcept
|
||||
{
|
||||
std::size_t res = is_command<T>::value ? 1 : 0;
|
||||
res += get_size_struct<0>(input, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Helper to serialize top-level messages
|
||||
template <typename Serializable, typename Allocator>
|
||||
void serialize_message(
|
||||
@@ -370,17 +224,30 @@ error_code deserialize_message(
|
||||
deserialization_context& ctx
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
// Dummy type to indicate no (de)serialization is required
|
||||
struct dummy_serializable
|
||||
{
|
||||
explicit dummy_serializable(...) {} // Make it constructible from anything
|
||||
};
|
||||
inline std::size_t get_size(dummy_serializable, const serialization_context&) noexcept { return 0; }
|
||||
inline void serialize(dummy_serializable, serialization_context&) noexcept {}
|
||||
inline errc deserialize(dummy_serializable, deserialization_context&) noexcept { return errc::ok; }
|
||||
|
||||
/*struct noop_serialization_traits
|
||||
{
|
||||
static inline std::size_t get_size_(dummy_serializable, const serialization_context&) noexcept { return 0; }
|
||||
static inline void serialize_(dummy_serializable, serialization_context&) noexcept {}
|
||||
static inline errc deserialize_(dummy_serializable, deserialization_context&) noexcept { return errc::ok; }
|
||||
};*/
|
||||
|
||||
struct noop_serialization_traits
|
||||
{
|
||||
static inline std::size_t get_size_(...) noexcept { return 0; }
|
||||
static inline void serialize_(...) noexcept {}
|
||||
static inline errc deserialize_(...) noexcept { return errc::ok; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct serialization_traits<dummy_serializable, no_serialization_tag> : noop_serialization_traits
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
// Helpers for (de) serializing a set of fields
|
||||
@@ -418,10 +285,30 @@ inline std::pair<error_code, std::uint8_t> deserialize_message_type(
|
||||
deserialization_context& ctx
|
||||
);
|
||||
|
||||
template <typename T>
|
||||
struct get_serialization_tag : std::conditional<
|
||||
is_fixed_size_int<T>(),
|
||||
fixed_size_int_tag,
|
||||
std::conditional_t<
|
||||
std::is_floating_point<T>::value,
|
||||
floating_point_tag,
|
||||
std::conditional_t<
|
||||
std::is_enum<T>::value,
|
||||
enum_tag,
|
||||
std::conditional_t<
|
||||
is_struct_with_fields<T>(),
|
||||
struct_tag,
|
||||
no_serialization_tag
|
||||
>
|
||||
>
|
||||
>
|
||||
> {};
|
||||
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
#include "boost/mysql/detail/protocol/impl/serialization.hpp"
|
||||
#include "boost/mysql/detail/protocol/impl/serialization.ipp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
#define TEST_SERIALIZATION_TEST_COMMON_HPP_
|
||||
|
||||
#include "boost/mysql/detail/protocol/serialization.hpp"
|
||||
#include "boost/mysql/detail/protocol/common_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/handshake_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/query_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/prepared_statement_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/constants.hpp"
|
||||
#include "boost/mysql/value.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
@@ -49,7 +45,7 @@ bool equals_struct(const T& lhs, const T& rhs)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_struct_with_fields<T>::value, bool>
|
||||
std::enable_if_t<is_struct_with_fields<T>(), bool>
|
||||
operator==(const T& lhs, const T& rhs)
|
||||
{
|
||||
return equals_struct<0>(lhs, rhs);
|
||||
@@ -84,7 +80,7 @@ void print_struct(std::ostream& os, const T& value)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<is_struct_with_fields<T>::value, std::ostream&>
|
||||
std::enable_if_t<is_struct_with_fields<T>(), std::ostream&>
|
||||
operator<<(std::ostream& os, const T& value)
|
||||
{
|
||||
os << boost::typeindex::type_id<T>().pretty_name() << "(\n";
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
*/
|
||||
|
||||
#include "serialization_test_common.hpp"
|
||||
#include "boost/mysql/detail/protocol/common_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/handshake_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/query_messages.hpp"
|
||||
#include "boost/mysql/detail/protocol/prepared_statement_messages.hpp"
|
||||
#include "test_common.hpp"
|
||||
#include <forward_list>
|
||||
#include <array>
|
||||
|
||||
Reference in New Issue
Block a user