userver: userver/storages/postgres/io/buffer_io.hpp Source File
Loading...
Searching...
No Matches
buffer_io.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/buffer_io.hpp
4/// @brief I/O buffer helpers
5
6#include <userver/storages/postgres/exceptions.hpp>
7#include <userver/storages/postgres/io/traits.hpp>
8
9USERVER_NAMESPACE_BEGIN
10
11namespace storages::postgres::io {
12
13namespace detail {
14
15template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
16struct ParserRequiresTypeCategories : std::false_type {};
17
18template <typename T>
19struct ParserRequiresTypeCategories<
20 T,
21 USERVER_NAMESPACE::utils::void_t<decltype(std::declval<T&>(
22 )(std::declval<const FieldBuffer&>(), std::declval<const TypeBufferCategory&>()))>> : std::true_type {};
23
24template <typename T>
25inline constexpr bool kParserRequiresTypeCategories =
26 ParserRequiresTypeCategories<typename traits::IO<T>::ParserType>::value;
27
28#ifndef NDEBUG
29
30class ReadersRegistrator final {
31public:
32 ReadersRegistrator(std::type_index type, std::type_index parser_type, const char* base_file);
33 void RequireInstance() const;
34};
35
36// Make instances with different __BASE_FILE__ differ for linker
37// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
38namespace {
39
40template <class Type, class Reader>
41struct CheckForBufferReaderODR final {
42 static inline ReadersRegistrator content{typeid(Type), typeid(Reader), __BASE_FILE__};
43};
44
45} // namespace
46
47class WritersRegistrator final {
48public:
49 WritersRegistrator(std::type_index type, std::type_index formatter_type, const char* base_file);
50 void RequireInstance() const;
51};
52
53// Make instances with different __BASE_FILE__ differ for linker
54// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
55namespace {
56
57template <class Type, class Writer>
58struct CheckForBufferWriterODR final {
59 static inline WritersRegistrator content{typeid(Type), typeid(Writer), __BASE_FILE__};
60};
61
62} // namespace
63#endif
64
65} // namespace detail
66
67/// @brief Read a value from input buffer
68template <typename T>
69void ReadBuffer(const FieldBuffer& buffer, T&& value) {
70 using ValueType = std::decay_t<T>;
71 traits::CheckParser<ValueType>();
72 using BufferReader = typename traits::IO<ValueType>::ParserType;
73 static_assert(
74 !detail::ParserRequiresTypeCategories<BufferReader>::value,
75 "Type parser requires knowledge about type categories"
76 );
77 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
78 throw InvalidParserCategory(
79 compiler::GetTypeName<ValueType>(), traits::kTypeBufferCategory<ValueType>, buffer.category
80 );
81 }
82
83#ifndef NDEBUG
84 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
85#endif
86 BufferReader{std::forward<T>(value)}(buffer);
87}
88
89template <typename T>
90void ReadBuffer(const FieldBuffer& buffer, T&& value, const TypeBufferCategory& categories) {
91 using ValueType = std::decay_t<T>;
92 traits::CheckParser<ValueType>();
93 using BufferReader = typename traits::IO<ValueType>::ParserType;
94 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
95 throw InvalidParserCategory(
96 compiler::GetTypeName<ValueType>(), traits::kTypeBufferCategory<ValueType>, buffer.category
97 );
98 }
99
100#ifndef NDEBUG
101 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
102#endif
103
104 if constexpr (detail::ParserRequiresTypeCategories<BufferReader>::value) {
105 BufferReader{std::forward<T>(value)}(buffer, categories);
106 } else {
107 BufferReader{std::forward<T>(value)}(buffer);
108 }
109}
110
111template <typename T>
112typename traits::IO<T>::FormatterType BufferWriter(const T& value) {
113 using Formatter = typename traits::IO<T>::FormatterType;
114#ifndef NDEBUG
115 detail::CheckForBufferWriterODR<T, Formatter>::content.RequireInstance();
116#endif
117 return Formatter(value);
118}
119
120template <typename T, typename Buffer>
121void WriteBuffer(const UserTypes& types, Buffer& buffer, const T& value) {
122 traits::CheckFormatter<T>();
123 BufferWriter(value)(types, buffer);
124}
125
126} // namespace storages::postgres::io
127
128USERVER_NAMESPACE_END