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 {
26 public:
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 std::string_view name) const;
104
105 /// @brief Erase data with specified name.
106 void EraseData(std::string_view name);
107
108 // TODO : TAXICOMMON-8252
109 impl::InternalRequestContext& GetInternalContext();
110
111 private:
112 utils::AnyMovable& SetUserAnyData(utils::AnyMovable&& data);
113 utils::AnyMovable& GetUserAnyData();
114 utils::AnyMovable* GetUserAnyDataOptional();
115 void EraseUserAnyData();
116
117 utils::AnyMovable& SetAnyData(std::string&& name, utils::AnyMovable&& data);
118 utils::AnyMovable& GetAnyData(std::string_view name);
119 utils::AnyMovable* GetAnyDataOptional(std::string_view name);
120 void EraseAnyData(std::string_view name);
121
122 class Impl;
123 static constexpr std::size_t kPimplSize = 112;
124 utils::FastPimpl<Impl, kPimplSize, alignof(void*)> impl_;
125};
126
127template <typename Data>
128Data& RequestContext::SetUserData(Data data) {
129 static_assert(!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 static_assert(
134 !std::is_reference_v<Data>,
135 "Data in RequestContext is stored by copy. Remove the reference "
136 "from the template parameter of SetUserData as it makes no sense");
137 return utils::AnyCast<Data&>(SetUserAnyData(std::move(data)));
138}
139
140template <typename Data, typename... Args>
141Data& RequestContext::EmplaceUserData(Args&&... args) {
142 // NOLINTNEXTLINE(google-readability-casting)
143 auto& data = SetUserAnyData(Data(std::forward<Args>(args)...));
144 return utils::AnyCast<Data&>(data);
145}
146
147template <typename Data>
148Data& RequestContext::GetUserData() {
149 return utils::AnyCast<Data&>(GetUserAnyData());
150}
151
152template <typename Data>
153const Data& RequestContext::GetUserData() const {
154 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
155 return const_cast<RequestContext*>(this)->GetUserData<Data>();
156}
157
158template <typename Data>
160 auto* data = GetUserAnyDataOptional();
161 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
162}
163
164template <typename Data>
166 const {
167 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
168 return const_cast<RequestContext*>(this)->GetUserDataOptional<Data>();
169}
170
171inline void RequestContext::EraseUserData() { EraseUserAnyData(); }
172
173template <typename Data>
174Data& RequestContext::SetData(std::string name, Data data) {
175 static_assert(!std::is_const_v<Data>,
176 "Data stored in RequestContext is mutable if RequestContext is "
177 "not `const`. Remove the `const` from the template parameter "
178 "of SetData as it makes no sense");
179 static_assert(
180 !std::is_reference_v<Data>,
181 "Data in RequestContext is stored by copy. Remove the reference "
182 "from the template parameter of SetData as it makes no sense");
183 return utils::AnyCast<Data&>(SetAnyData(std::move(name), std::move(data)));
184}
185
186template <typename Data, typename... Args>
187Data& RequestContext::EmplaceData(std::string name, Args&&... args) {
188 // NOLINTNEXTLINE(google-readability-casting)
189 auto& data = SetAnyData(std::move(name), Data(std::forward<Args>(args)...));
190 return utils::AnyCast<Data&>(data);
191}
192
193template <typename Data>
194Data& RequestContext::GetData(std::string_view name) {
195 return utils::AnyCast<Data&>(GetAnyData(name));
196}
197
198template <typename Data>
199const Data& RequestContext::GetData(std::string_view name) const {
200 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
201 return const_cast<RequestContext*>(this)->GetData<Data>(name);
202}
203
204template <typename Data>
207 auto* data = GetAnyDataOptional(name);
208 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
209}
210
211template <typename Data>
213 std::string_view name) const {
214 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
215 return const_cast<RequestContext*>(this)->GetDataOptional<Data>(name);
216}
217
218inline void RequestContext::EraseData(std::string_view name) {
219 EraseAnyData(name);
220}
221
222} // namespace server::request
223
224USERVER_NAMESPACE_END