userver: userver/storages/postgres/io/buffer_io.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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, USERVER_NAMESPACE::utils::void_t<decltype(std::declval<T&>()(
21 std::declval<const FieldBuffer&>(),
22 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 {
31 public:
32 ReadersRegistrator(std::type_index type, std::type_index parser_type,
33 const char* base_file);
34 void RequireInstance() const;
35};
36
37// Make instances with different __BASE_FILE__ differ for linker
38// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
39namespace {
40
41template <class Type, class Reader>
42struct CheckForBufferReaderODR final {
43 static inline ReadersRegistrator content{typeid(Type), typeid(Reader),
44 __BASE_FILE__};
45};
46
47} // namespace
48
49class WritersRegistrator final {
50 public:
51 WritersRegistrator(std::type_index type, std::type_index formatter_type,
52 const char* base_file);
53 void RequireInstance() const;
54};
55
56// Make instances with different __BASE_FILE__ differ for linker
57// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
58namespace {
59
60template <class Type, class Writer>
61struct CheckForBufferWriterODR final {
62 static inline WritersRegistrator content{typeid(Type), typeid(Writer),
63 __BASE_FILE__};
64};
65
66} // namespace
67#endif
68
69} // namespace detail
70
71/// @brief Read a value from input buffer
72template <typename T>
73void ReadBuffer(const FieldBuffer& buffer, T&& value) {
74 using ValueType = std::decay_t<T>;
75 traits::CheckParser<ValueType>();
76 using BufferReader = typename traits::IO<ValueType>::ParserType;
77 static_assert(!detail::ParserRequiresTypeCategories<BufferReader>::value,
78 "Type parser requires knowledge about type categories");
79 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
80 throw InvalidParserCategory(compiler::GetTypeName<ValueType>(),
81 traits::kTypeBufferCategory<ValueType>,
82 buffer.category);
83 }
84
85#ifndef NDEBUG
86 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
87#endif
88 BufferReader{std::forward<T>(value)}(buffer);
89}
90
91template <typename T>
92void ReadBuffer(const FieldBuffer& buffer, T&& value,
93 const TypeBufferCategory& categories) {
94 using ValueType = std::decay_t<T>;
95 traits::CheckParser<ValueType>();
96 using BufferReader = typename traits::IO<ValueType>::ParserType;
97 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
98 throw InvalidParserCategory(compiler::GetTypeName<ValueType>(),
99 traits::kTypeBufferCategory<ValueType>,
100 buffer.category);
101 }
102
103#ifndef NDEBUG
104 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
105#endif
106
107 if constexpr (detail::ParserRequiresTypeCategories<BufferReader>::value) {
108 BufferReader{std::forward<T>(value)}(buffer, categories);
109 } else {
110 BufferReader{std::forward<T>(value)}(buffer);
111 }
112}
113
114template <typename T>
115typename traits::IO<T>::FormatterType BufferWriter(const T& value) {
116 using Formatter = typename traits::IO<T>::FormatterType;
117#ifndef NDEBUG
118 detail::CheckForBufferWriterODR<T, Formatter>::content.RequireInstance();
119#endif
120 return Formatter(value);
121}
122
123template <typename T, typename Buffer>
124void WriteBuffer(const UserTypes& types, Buffer& buffer, const T& value) {
125 traits::CheckFormatter<T>();
126 BufferWriter(value)(types, buffer);
127}
128
129} // namespace storages::postgres::io
130
131USERVER_NAMESPACE_END