8#include <unordered_map> 
   10#include <userver/storages/postgres/io/buffer_io.hpp> 
   11#include <userver/storages/postgres/io/buffer_io_base.hpp> 
   12#include <userver/storages/postgres/io/pg_types.hpp> 
   13#include <userver/storages/postgres/io/type_mapping.hpp> 
   14#include <userver/storages/postgres/io/user_types.hpp> 
   15#include <userver/utils/trivial_map_fwd.hpp> 
   17#include <userver/storages/postgres/detail/string_hash.hpp> 
   19USERVER_NAMESPACE_BEGIN
 
   26template <
typename Enum>
 
   29  std::string_view literal;
 
   31  constexpr Enumerator(Enum en, std::string_view lit)
 
   32      : enumerator{en}, literal{lit} {}
 
   39template <
typename Enum>
 
   41  static_assert(std::is_enum<Enum>(), 
"Type must be an enumeration");
 
   48  using EnumType = Enum;
 
   51  using Enumerator = detail::Enumerator<Enum>;
 
   56  using EnumeratorList = 
const std::initializer_list<Enumerator>;
 
   61template <
typename Enum, 
typename Enable = USERVER_NAMESPACE::utils::void_t<>>
 
   62struct AreEnumeratorsDefined : std::false_type {};
 
   64template <
typename Enum>
 
   65struct AreEnumeratorsDefined<
 
   67    USERVER_NAMESPACE::utils::void_t<
decltype(CppToUserPg<Enum>::enumerators)*>>
 
   70template <
typename Enum>
 
   72  static_assert(std::is_enum<Enum>(), 
"Type must be an enumeration");
 
   73  static_assert(AreEnumeratorsDefined<Enum>(),
 
   74                "CppToUserPg for an enumeration must contain a static " 
   75                "`enumerators` member of `utils::TrivialBiMap` type or " 
   76                "`storages::postgres::io::detail::Enumerator[]`");
 
   77  using Type = 
decltype(CppToUserPg<Enum>::enumerators);
 
   80template <
typename Enum, 
typename = 
typename Enumerators<Enum>::Type>
 
   83template <
typename Enum, 
typename T>
 
   85  using StringType = std::string_view;
 
   86  using EnumType = Enum;
 
   87  using MappingType = CppToUserPg<EnumType>;
 
   88  using EnumeratorType = Enumerator<EnumType>;
 
   91    std::size_t operator()(EnumType v) 
const {
 
   92      using underlying_type = std::underlying_type_t<EnumType>;
 
   93      using hasher = std::hash<underlying_type>;
 
   94      return hasher{}(
static_cast<underlying_type>(v));
 
   98  using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
 
  100      std::unordered_map<StringType, EnumType, utils::StringViewHash>;
 
  101  using MapsPair = std::pair<EnumToString, StringToEnum>;
 
  103  static MapsPair MapLiterals() {
 
  105    for (
const auto& enumerator : enumerators) {
 
  107          std::make_pair(enumerator.enumerator, enumerator.literal));
 
  109          std::make_pair(enumerator.literal, enumerator.enumerator));
 
  113  static const MapsPair& GetMaps() {
 
  114    static auto maps_ = MapLiterals();
 
  117  static const EnumToString& EnumeratorMap() { 
return GetMaps().first; }
 
  118  static const StringToEnum& LiteralMap() { 
return GetMaps().second; }
 
  121  static constexpr const auto& enumerators = MappingType::enumerators;
 
  122  static constexpr std::size_t size = std::size(enumerators);
 
  123  static EnumType GetEnumerator(StringType literal) {
 
  124    static const auto& map = LiteralMap();
 
  125    if (
auto f = map.find(literal); f != map.end()) {
 
  128    throw InvalidEnumerationLiteral{
 
  129        compiler::GetTypeName<EnumType>(),
 
  130        std::string{literal.data(), literal.size()}};
 
  132  static StringType GetLiteral(EnumType enumerator) {
 
  133    static const auto& map = EnumeratorMap();
 
  134    if (
auto f = map.find(enumerator); f != map.end()) {
 
  141template <
typename Enum, 
typename Func>
 
  142class EnumerationMap<Enum, 
const USERVER_NAMESPACE::utils::TrivialBiMap<Func>> {
 
  143  using StringType = std::string_view;
 
  144  using EnumType = Enum;
 
  145  using MappingType = CppToUserPg<EnumType>;
 
  148  static constexpr const auto& enumerators = MappingType::enumerators;
 
  149  static constexpr std::size_t size = enumerators.size();
 
  150  static constexpr EnumType GetEnumerator(StringType literal) {
 
  151    auto enumerator = enumerators.TryFind(literal);
 
  152    if (enumerator.has_value()) 
return *enumerator;
 
  153    throw InvalidEnumerationLiteral{
 
  154        compiler::GetTypeName<EnumType>(),
 
  155        std::string{literal.data(), literal.size()}};
 
  157  static constexpr StringType GetLiteral(EnumType enumerator) {
 
  158    auto literal = enumerators.TryFind(enumerator);
 
  159    if (literal.has_value()) 
return *literal;
 
  164template <
typename Enum>
 
  165struct EnumParser : BufferParserBase<Enum> {
 
  166  using BaseType = BufferParserBase<Enum>;
 
  167  using EnumMap = EnumerationMap<Enum>;
 
  169  using BaseType::BaseType;
 
  172    std::string_view literal;
 
  173    io::ReadBuffer(buffer, literal);
 
  174    this->value = EnumMap::GetEnumerator(literal);
 
  178template <
typename Enum>
 
  179struct EnumFormatter : BufferFormatterBase<Enum> {
 
  180  using BaseType = BufferFormatterBase<Enum>;
 
  181  using EnumMap = EnumerationMap<Enum>;
 
  183  using BaseType::BaseType;
 
  185  template <
typename Buffer>
 
  186  void operator()(
const UserTypes& types, Buffer& buffer) 
const {
 
  187    auto literal = EnumMap::GetLiteral(
this->value);
 
  188    io::WriteBuffer(types, buffer, literal);