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) : enumerator{en}, literal{lit} {}
38template <
typename Enum>
40 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
47 using EnumType = Enum;
50 using Enumerator = detail::Enumerator<Enum>;
55 using EnumeratorList =
const std::initializer_list<Enumerator>;
64template <
typename Enum,
typename Enable = USERVER_NAMESPACE::utils::void_t<>>
65struct AreEnumeratorsDefined : std::false_type {};
67template <
typename Enum>
68struct AreEnumeratorsDefined<Enum, USERVER_NAMESPACE::utils::void_t<
decltype(CppToUserPg<Enum>::enumerators)*>>
71template <
typename Enum>
73 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
75 AreEnumeratorsDefined<Enum>(),
76 "CppToUserPg for an enumeration must contain a static "
77 "`enumerators` member of `utils::TrivialBiMap` type or "
78 "`storages::postgres::io::detail::Enumerator[]`"
80 using Type =
decltype(CppToUserPg<Enum>::enumerators);
83template <
typename Enum,
typename =
typename Enumerators<Enum>::Type>
86template <
typename Enum,
typename T>
88 using StringType = std::string_view;
89 using EnumType = Enum;
90 using MappingType = CppToUserPg<EnumType>;
91 using EnumeratorType = Enumerator<EnumType>;
94 std::size_t operator()(EnumType v)
const {
95 using underlying_type = std::underlying_type_t<EnumType>;
96 using hasher = std::hash<underlying_type>;
97 return hasher{}(
static_cast<underlying_type>(v));
101 using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
102 using StringToEnum = std::unordered_map<StringType, EnumType, utils::StringViewHash>;
103 using MapsPair = std::pair<EnumToString, StringToEnum>;
105 static MapsPair MapLiterals() {
107 for (
const auto& enumerator : enumerators) {
108 maps.first.insert(std::make_pair(enumerator.enumerator, enumerator.literal));
109 maps.second.insert(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{compiler::GetTypeName<EnumType>(), std::string{literal.data(), literal.size()}};
130 static StringType GetLiteral(EnumType enumerator) {
131 static const auto& map = EnumeratorMap();
132 if (
auto f = map.find(enumerator); f != map.end()) {
139template <
typename Enum,
typename Func>
140class EnumerationMap<Enum,
const USERVER_NAMESPACE::
utils::TrivialBiMap<Func>> {
141 using StringType = std::string_view;
142 using EnumType = Enum;
143 using MappingType = CppToUserPg<EnumType>;
146 static constexpr const auto& enumerators = MappingType::enumerators;
147 static constexpr std::size_t size = enumerators.size();
148 static constexpr EnumType GetEnumerator(StringType literal) {
149 auto enumerator = enumerators.TryFind(literal);
150 if (enumerator.has_value())
return *enumerator;
151 throw InvalidEnumerationLiteral{compiler::GetTypeName<EnumType>(), std::string{literal.data(), literal.size()}};
153 static constexpr StringType GetLiteral(EnumType enumerator) {
154 auto literal = enumerators.TryFind(enumerator);
155 if (literal.has_value())
return *literal;
160template <
typename Enum>
161class EnumerationMap<Enum,
const Codegen> {
162 using EnumType = Enum;
163 using MappingType = CppToUserPg<EnumType>;
166 static EnumType GetEnumerator(std::string_view literal) {
return Parse(literal, formats::parse::To<Enum>{}); }
167 static std::string GetLiteral(EnumType enumerator) {
return ToString(enumerator); }
170template <
typename Enum>
171struct EnumParser : BufferParserBase<Enum> {
172 using BaseType = BufferParserBase<Enum>;
173 using EnumMap = EnumerationMap<Enum>;
175 using BaseType::BaseType;
178 std::string_view literal;
179 io::ReadBuffer(buffer, literal);
180 this->value = EnumMap::GetEnumerator(literal);
184template <
typename Enum>
185struct EnumFormatter : BufferFormatterBase<Enum> {
186 using BaseType = BufferFormatterBase<Enum>;
187 using EnumMap = EnumerationMap<Enum>;
189 using BaseType::BaseType;
191 template <
typename Buffer>
192 void operator()(
const UserTypes& types, Buffer& buffer)
const {
193 auto literal = EnumMap::GetLiteral(
this->value);
194 io::WriteBuffer(types, buffer, literal);