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, 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