Sindbad~EG File Manager
//
// Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP
#define BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP
#include <boost/mysql/client_errc.hpp>
#include <boost/mysql/date.hpp>
#include <boost/mysql/datetime.hpp>
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_kind.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/time.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/typing/meta_check_context.hpp>
#include <boost/mysql/detail/typing/pos_map.hpp>
#include <boost/mysql/detail/void_t.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>
#include <cstdint>
#include <limits>
#include <string>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Helpers for integers
template <class SignedInt>
error_code parse_signed_int(field_view input, SignedInt& output)
{
using unsigned_t = typename std::make_unsigned<SignedInt>::type;
using limits_t = std::numeric_limits<SignedInt>;
auto kind = input.kind();
if (kind == field_kind::int64)
{
auto v = input.get_int64();
if (v < (limits_t::min)() || v > (limits_t::max)())
{
return client_errc::static_row_parsing_error;
}
output = static_cast<SignedInt>(v);
return error_code();
}
else if (kind == field_kind::uint64)
{
auto v = input.get_uint64();
if (v > static_cast<unsigned_t>((limits_t::max)()))
{
return client_errc::static_row_parsing_error;
}
output = static_cast<SignedInt>(v);
return error_code();
}
else
{
return client_errc::static_row_parsing_error;
}
}
template <class UnsignedInt>
error_code parse_unsigned_int(field_view input, UnsignedInt& output)
{
if (input.kind() != field_kind::uint64)
{
return client_errc::static_row_parsing_error;
}
auto v = input.get_uint64();
if (v > (std::numeric_limits<UnsignedInt>::max)())
{
return client_errc::static_row_parsing_error;
}
output = static_cast<UnsignedInt>(v);
return error_code();
}
// We want all integer types to be allowed as fields. Some integers
// may have the same width as others, but different type (e.g. long and long long
// may both be 64-bit, but different types). Auxiliar int_traits to allow this to work
template <class T, bool is_signed = std::is_signed<T>::value, std::size_t width = sizeof(T)>
struct int_traits
{
static constexpr bool is_supported = false;
};
template <class T>
struct int_traits<T, true, 1>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "int8_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 1>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "uint8_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 2>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "int16_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return true;
case column_type::smallint:
case column_type::year: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 2>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "uint16_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 4>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "int32_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint: return true;
case column_type::int_: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 4>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "uint32_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 8>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "int64_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_: return true;
case column_type::bigint: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 8>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "uint64_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_:
case column_type::bigint: return ctx.current_meta().is_unsigned();
case column_type::bit: return true;
default: return false;
}
}
static error_code parse(field_view input, std::uint64_t& output)
{
return parse_unsigned_int(input, output);
}
};
// Traits
template <typename T, class EnableIf = void>
struct readable_field_traits
{
static constexpr bool is_supported = false;
};
template <>
struct readable_field_traits<char, void> : int_traits<char>
{
};
template <>
struct readable_field_traits<signed char, void> : int_traits<signed char>
{
};
template <>
struct readable_field_traits<unsigned char, void> : int_traits<unsigned char>
{
};
template <>
struct readable_field_traits<short, void> : int_traits<short>
{
};
template <>
struct readable_field_traits<unsigned short, void> : int_traits<unsigned short>
{
};
template <>
struct readable_field_traits<int, void> : int_traits<int>
{
};
template <>
struct readable_field_traits<unsigned int, void> : int_traits<unsigned int>
{
};
template <>
struct readable_field_traits<long, void> : int_traits<long>
{
};
template <>
struct readable_field_traits<unsigned long, void> : int_traits<unsigned long>
{
};
template <>
struct readable_field_traits<long long, void> : int_traits<long long>
{
};
template <>
struct readable_field_traits<unsigned long long, void> : int_traits<unsigned long long>
{
};
template <>
struct readable_field_traits<bool, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "bool";
static bool meta_check(meta_check_context& ctx)
{
return ctx.current_meta().type() == column_type::tinyint && !ctx.current_meta().is_unsigned();
}
static error_code parse(field_view input, bool& output)
{
if (input.kind() != field_kind::int64)
{
return client_errc::static_row_parsing_error;
}
output = input.get_int64() != 0;
return error_code();
}
};
template <>
struct readable_field_traits<float, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "float";
static bool meta_check(meta_check_context& ctx)
{
return ctx.current_meta().type() == column_type::float_;
}
static error_code parse(field_view input, float& output)
{
if (input.kind() != field_kind::float_)
{
return client_errc::static_row_parsing_error;
}
output = input.get_float();
return error_code();
}
};
template <>
struct readable_field_traits<double, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "double";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::float_:
case column_type::double_: return true;
default: return false;
}
}
static error_code parse(field_view input, double& output)
{
auto kind = input.kind();
if (kind == field_kind::float_)
{
output = input.get_float();
return error_code();
}
else if (kind == field_kind::double_)
{
output = input.get_double();
return error_code();
}
else
{
return client_errc::static_row_parsing_error;
}
}
};
template <class Allocator>
struct readable_field_traits<std::basic_string<char, std::char_traits<char>, Allocator>, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "string";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::decimal:
case column_type::char_:
case column_type::varchar:
case column_type::text:
case column_type::enum_:
case column_type::set:
case column_type::json: return true;
default: return false;
}
}
static error_code parse(
field_view input,
std::basic_string<char, std::char_traits<char>, Allocator>& output
)
{
if (input.kind() != field_kind::string)
{
return client_errc::static_row_parsing_error;
}
output = input.get_string();
return error_code();
}
};
template <class Allocator>
struct readable_field_traits<std::vector<unsigned char, Allocator>, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "blob";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::binary:
case column_type::varbinary:
case column_type::blob:
case column_type::geometry:
case column_type::unknown: return true;
default: return false;
}
}
static error_code parse(field_view input, std::vector<unsigned char, Allocator>& output)
{
if (input.kind() != field_kind::blob)
{
return client_errc::static_row_parsing_error;
}
auto view = input.get_blob();
output.assign(view.begin(), view.end());
return error_code();
}
};
template <>
struct readable_field_traits<date, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "date";
static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::date; }
static error_code parse(field_view input, date& output)
{
if (input.kind() != field_kind::date)
{
return client_errc::static_row_parsing_error;
}
output = input.get_date();
return error_code();
}
};
template <>
struct readable_field_traits<datetime, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "datetime";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::datetime:
case column_type::timestamp: return true;
default: return false;
}
}
static error_code parse(field_view input, datetime& output)
{
if (input.kind() != field_kind::datetime)
{
return client_errc::static_row_parsing_error;
}
output = input.get_datetime();
return error_code();
}
};
template <>
struct readable_field_traits<time, void>
{
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = "time";
static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::time; }
static error_code parse(field_view input, time& output)
{
if (input.kind() != field_kind::time)
{
return client_errc::static_row_parsing_error;
}
output = input.get_time();
return error_code();
}
};
// std::optional<T> and boost::optional<T>. To avoid dependencies,
// this is achieved through a "concept"
template <class T, class = void>
struct is_readable_optional : std::false_type
{
};
template <class T>
struct is_readable_optional<
T,
void_t<
typename std::enable_if<
std::is_same<decltype(std::declval<T&>().value()), typename T::value_type&>::value>::type,
decltype(std::declval<T&>().emplace()), // T should be default constructible
decltype(std::declval<T&>().reset())>> : std::true_type
{
};
template <class T>
struct readable_field_traits<
T,
typename std::enable_if<
is_readable_optional<T>::value && readable_field_traits<typename T::value_type>::is_supported>::type>
{
using value_type = typename T::value_type;
static constexpr bool is_supported = true;
static BOOST_INLINE_CONSTEXPR const char* type_name = readable_field_traits<value_type>::type_name;
static bool meta_check(meta_check_context& ctx)
{
ctx.set_nullability_checked();
return readable_field_traits<value_type>::meta_check(ctx);
}
static error_code parse(field_view input, T& output)
{
if (input.is_null())
{
output.reset();
return error_code();
}
else
{
output.emplace();
return readable_field_traits<value_type>::parse(input, output.value());
}
}
};
template <class T>
struct is_readable_field
{
static constexpr bool value = readable_field_traits<T>::is_supported;
};
template <typename ReadableField>
void meta_check_field_impl(meta_check_context& ctx)
{
using traits_t = readable_field_traits<ReadableField>;
// Verify that the field is present
if (ctx.is_current_field_absent())
{
ctx.add_field_absent_error();
return;
}
// Perform the check
bool ok = traits_t::meta_check(ctx);
if (!ok)
{
ctx.add_type_mismatch_error(traits_t::type_name);
}
// Check nullability
if (!ctx.nullability_checked() && !ctx.current_meta().is_not_null())
{
ctx.add_nullability_error();
}
}
template <typename ReadableField>
void meta_check_field(meta_check_context& ctx)
{
static_assert(is_readable_field<ReadableField>::value, "Should be a ReadableField");
meta_check_field_impl<ReadableField>(ctx);
ctx.advance();
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists