userver: userver/server/request/request_context.hpp Source File
Loading...
Searching...
No Matches
request_context.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/request/request_context.hpp
4/// @brief @copybrief server::request::RequestContext
5
6#include <string>
7#include <string_view>
8#include <type_traits>
9
10#include <userver/utils/any_movable.hpp>
11#include <userver/utils/fast_pimpl.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace server::request {
16
17namespace impl {
18class InternalRequestContext;
19}
20
21/// @brief Stores request-specific data during request processing.
22///
23/// For example: you can store some data in `HandleRequestThrow()` method
24/// and access this data in `GetResponseDataForLogging()` method.
25class RequestContext final {
26public:
27 RequestContext();
28
29 RequestContext(RequestContext&&) noexcept;
30
31 RequestContext(const RequestContext&) = delete;
32
33 ~RequestContext();
34
35 /// @brief Stores user data if it was not previously stored in this.
36 /// @throw std::runtime_error if user data was already stored.
37 template <typename Data>
38 Data& SetUserData(Data data);
39
40 /// @brief Emplaces user data if it was not previously stored in this.
41 /// @throw std::runtime_error if user data was already stored.
42 template <typename Data, typename... Args>
43 Data& EmplaceUserData(Args&&... args);
44
45 /// @returns Stored user data
46 /// @throws std::runtime_error if no data was stored
47 /// @throws std::bad_any_cast if data of different type was stored
48 template <typename Data>
49 Data& GetUserData();
50
51 /// @returns Stored user data
52 /// @throws std::runtime_error if no data was stored
53 /// @throws std::bad_any_cast if data of different type was stored
54 template <typename Data>
55 const Data& GetUserData() const;
56
57 /// @returns A pointer to data of type Data if it was stored before during
58 /// current request processing or nullptr otherwise
59 template <typename Data>
61
62 /// @returns A pointer to data of type Data if it was stored before during
63 /// current request processing or nullptr otherwise
64 template <typename Data>
66
67 /// @brief Erases the user data.
68 void EraseUserData();
69
70 /// @brief Stores the data with specified name if it was not previously stored
71 /// in this.
72 /// @throw std::runtime_error if data with such name was already stored.
73 template <typename Data>
74 Data& SetData(std::string name, Data data);
75
76 /// @brief Emplaces the data with specified name if it was not previously
77 /// stored in this.
78 /// @throw std::runtime_error if data with such name was already stored.
79 template <typename Data, typename... Args>
80 Data& EmplaceData(std::string name, Args&&... args);
81
82 /// @returns Stored data with specified name.
83 /// @throws std::runtime_error if no data was stored
84 /// @throws std::bad_any_cast if data of different type was stored
85 template <typename Data>
86 Data& GetData(std::string_view name);
87
88 /// @returns Stored data with specified name.
89 /// @throws std::runtime_error if no data was stored
90 /// @throws std::bad_any_cast if data of different type was stored
91 template <typename Data>
92 const Data& GetData(std::string_view name) const;
93
94 /// @returns Stored data with specified name or nullptr if no data found.
95 /// @throws std::bad_any_cast if data of different type was stored.
96 template <typename Data>
98
99 /// @returns Stored data with specified name or nullptr if no data found.
100 /// @throws std::bad_any_cast if data of different type was stored.
101 template <typename Data>
103
104 /// @brief Erase data with specified name.
105 void EraseData(std::string_view name);
106
107 // TODO : TAXICOMMON-8252
108 impl::InternalRequestContext& GetInternalContext();
109
110private:
111 utils::AnyMovable& SetUserAnyData(utils::AnyMovable&& data);
112 utils::AnyMovable& GetUserAnyData();
113 utils::AnyMovable* GetUserAnyDataOptional();
114 void EraseUserAnyData();
115
116 utils::AnyMovable& SetAnyData(std::string&& name, utils::AnyMovable&& data);
117 utils::AnyMovable& GetAnyData(std::string_view name);
118 utils::AnyMovable* GetAnyDataOptional(std::string_view name);
119 void EraseAnyData(std::string_view name);
120
121 class Impl;
122 static constexpr std::size_t kPimplSize = 112;
123 utils::FastPimpl<Impl, kPimplSize, alignof(void*)> impl_;
124};
125
126template <typename Data>
127Data& RequestContext::SetUserData(Data data) {
128 static_assert(
129 !std::is_const_v<Data>,
130 "Data stored in RequestContext is mutable if RequestContext is "
131 "not `const`. Remove the `const` from the template parameter "
132 "of SetUserData as it makes no sense"
133 );
134 static_assert(
135 !std::is_reference_v<Data>,
136 "Data in RequestContext is stored by copy. Remove the reference "
137 "from the template parameter of SetUserData as it makes no sense"
138 );
139 return utils::AnyCast<Data&>(SetUserAnyData(std::move(data)));
140}
141
142template <typename Data, typename... Args>
143Data& RequestContext::EmplaceUserData(Args&&... args) {
144 // NOLINTNEXTLINE(google-readability-casting)
145 auto& data = SetUserAnyData(Data(std::forward<Args>(args)...));
146 return utils::AnyCast<Data&>(data);
147}
148
149template <typename Data>
150Data& RequestContext::GetUserData() {
151 return utils::AnyCast<Data&>(GetUserAnyData());
152}
153
154template <typename Data>
155const Data& RequestContext::GetUserData() const {
156 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
157 return const_cast<RequestContext*>(this)->GetUserData<Data>();
158}
159
160template <typename Data>
162 auto* data = GetUserAnyDataOptional();
163 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
164}
165
166template <typename Data>
167const std::remove_reference_t<Data>* RequestContext::GetUserDataOptional() const {
168 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
169 return const_cast<RequestContext*>(this)->GetUserDataOptional<Data>();
170}
171
172inline void RequestContext::EraseUserData() { EraseUserAnyData(); }
173
174template <typename Data>
175Data& RequestContext::SetData(std::string name, Data data) {
176 static_assert(
177 !std::is_const_v<Data>,
178 "Data stored in RequestContext is mutable if RequestContext is "
179 "not `const`. Remove the `const` from the template parameter "
180 "of SetData as it makes no sense"
181 );
182 static_assert(
183 !std::is_reference_v<Data>,
184 "Data in RequestContext is stored by copy. Remove the reference "
185 "from the template parameter of SetData as it makes no sense"
186 );
187 return utils::AnyCast<Data&>(SetAnyData(std::move(name), std::move(data)));
188}
189
190template <typename Data, typename... Args>
191Data& RequestContext::EmplaceData(std::string name, Args&&... args) {
192 // NOLINTNEXTLINE(google-readability-casting)
193 auto& data = SetAnyData(std::move(name), Data(std::forward<Args>(args)...));
194 return utils::AnyCast<Data&>(data);
195}
196
197template <typename Data>
198Data& RequestContext::GetData(std::string_view name) {
199 return utils::AnyCast<Data&>(GetAnyData(name));
200}
201
202template <typename Data>
203const Data& RequestContext::GetData(std::string_view name) const {
204 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
205 return const_cast<RequestContext*>(this)->GetData<Data>(name);
206}
207
208template <typename Data>
210 auto* data = GetAnyDataOptional(name);
211 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
212}
213
214template <typename Data>
216 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
217 return const_cast<RequestContext*>(this)->GetDataOptional<Data>(name);
218}
219
220inline void RequestContext::EraseData(std::string_view name) { EraseAnyData(name); }
221
222} // namespace server::request
223
224USERVER_NAMESPACE_END