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);