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<
22 decltype(std::declval<T&>()(std::declval<const FieldBuffer&>(), std::declval<const TypeBufferCategory&>()))>>
23 : std::true_type {};
24
25template <typename T>
26inline constexpr bool
27 kParserRequiresTypeCategories = ParserRequiresTypeCategories<typename traits::IO<T>::ParserType>::value;
28
29#ifndef NDEBUG
30
31class ReadersRegistrator final {
32public:
33 ReadersRegistrator(std::type_index type, std::type_index parser_type, 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), __BASE_FILE__};
44};
45
46} // namespace
47
48class WritersRegistrator final {
49public:
50 WritersRegistrator(std::type_index type, std::type_index formatter_type, const char* base_file);
51 void RequireInstance() const;
52};
53
54// Make instances with different __BASE_FILE__ differ for linker
55// NOLINTNEXTLINE(cert-dcl59-cpp,google-build-namespaces)
56namespace {
57
58template <class Type, class Writer>
59struct CheckForBufferWriterODR final {
60 static inline WritersRegistrator content{typeid(Type), typeid(Writer), __BASE_FILE__};
61};
62
63} // namespace
64#endif
65
66} // namespace detail
67
68/// @brief Read a value from input buffer
69template <typename T>
70void ReadBuffer(const FieldBuffer& buffer, T&& value) {
71 using ValueType = std::decay_t<T>;
72 traits::CheckParser<ValueType>();
73 using BufferReader = typename traits::IO<ValueType>::ParserType;
74 static_assert(
75 !detail::ParserRequiresTypeCategories<BufferReader>::value,
76 "Type parser requires knowledge about type categories"
77 );
78 if (traits::kParserBufferCategory<BufferReader> != buffer.category) {
80 compiler::GetTypeName<ValueType>(),
81 traits::kTypeBufferCategory<ValueType>,
82 buffer.category
83 );
84 }
85
86#ifndef NDEBUG
87 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
88#endif
89 BufferReader{std::forward<T>(value)}(buffer);
90}
91
92template <typename T>
93void ReadBuffer(const FieldBuffer& buffer, T&& value, 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) {
99 compiler::GetTypeName<ValueType>(),
100 traits::kTypeBufferCategory<ValueType>,
101 buffer.category
102 );
103 }
104
105#ifndef NDEBUG
106 detail::CheckForBufferReaderODR<T, BufferReader>::content.RequireInstance();
107#endif
108
109 if constexpr (detail::ParserRequiresTypeCategories<BufferReader>::value) {
110 BufferReader{std::forward<T>(value)}(buffer, categories);
111 } else {
112 BufferReader{std::forward<T>(value)}(buffer);
113 }
114}
115
116template <typename T>
117typename traits::IO<T>::FormatterType BufferWriter(const T& value) {
118 using Formatter = typename traits::IO<T>::FormatterType;
119#ifndef NDEBUG
120 detail::CheckForBufferWriterODR<T, Formatter>::content.RequireInstance();
121#endif
122 return Formatter(value);
123}
124
125template <typename T, typename Buffer>
126void WriteBuffer(const UserTypes& types, Buffer& buffer, const T& value) {
127 traits::CheckFormatter<T>();
128 BufferWriter(value)(types, buffer);
129}
130
131} // namespace storages::postgres::io
132
133USERVER_NAMESPACE_END