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 Parser>
16concept ParserCallableWithCategories = requires(Parser& p, const FieldBuffer& fb, const TypeBufferCategory& cats) {
17 p(fb, cats);
18};
19
20template <typename ValueType>
21// NOLINTNEXTLINE(readability-identifier-naming)
22concept kParserRequiresTypeCategories = ParserCallableWithCategories<typename traits::IO<ValueType>::ParserType>;
23
24#ifndef NDEBUG
25
26class ReadersRegistrator final {
27public:
28 ReadersRegistrator(std::type_index type, std::type_index parser_type, const char* base_file);
29 void RequireInstance() const;
30};
31
32// Make instances with different __BASE_FILE__ differ for linker
33// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
34namespace {
35
36template <class Type, class Reader>
37struct CheckForBufferReaderODR final {
38 static inline ReadersRegistrator content{typeid(Type), typeid(Reader), __BASE_FILE__};
39};
40
41} // namespace
42
43class WritersRegistrator final {
44public:
45 WritersRegistrator(std::type_index type, std::type_index formatter_type, const char* base_file);
46 void RequireInstance() const;
47};
48
49// Make instances with different __BASE_FILE__ differ for linker
50// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
51namespace {
52
53template <class Type, class Writer>
54struct CheckForBufferWriterODR final {
55 static inline WritersRegistrator content{typeid(Type), typeid(Writer), __BASE_FILE__};
56};
57
58} // namespace
59#endif
60
61} // namespace detail
62
63/// @brief Read a value from input buffer
64template <typename T>
65void ReadBuffer(const FieldBuffer& buffer, T&& value) {
66 using ValueType = std::remove_cvref_t<T>;
67 traits::CheckParser<ValueType>();
68 using BufferReader = typename traits::IO<ValueType>::ParserType;
69 static_assert(
70 !detail::ParserCallableWithCategories<BufferReader>,
71 "Type parser requires knowledge about type categories"
72 );
73 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
75 compiler::GetTypeName<ValueType>(),
76 traits::kTypeBufferCategory<ValueType>,
77 buffer.category
78 );
79 }
80
81#ifndef NDEBUG
82 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
83#endif
84 BufferReader{std::forward<T>(value)}(buffer);
85}
86
87template <typename T>
88void ReadBuffer(const FieldBuffer& buffer, T&& value, const TypeBufferCategory& categories) {
89 using ValueType = std::remove_cvref_t<T>;
90 traits::CheckParser<ValueType>();
91 using BufferReader = typename traits::IO<ValueType>::ParserType;
92 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
94 compiler::GetTypeName<ValueType>(),
95 traits::kTypeBufferCategory<ValueType>,
96 buffer.category
97 );
98 }
99
100#ifndef NDEBUG
101 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
102#endif
103
104 if constexpr (detail::ParserCallableWithCategories<BufferReader>) {
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