TrinityCore
Loading...
Searching...
No Matches
ExpectedCompletionHandler.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H
19#define TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H
20
21#include <boost/asio/associated_executor.hpp>
22#include <boost/asio/async_result.hpp>
23#include <boost/asio/handler_continuation_hook.hpp>
24#include <boost/outcome/result.hpp>
25#include <boost/preprocessor/empty.hpp>
26#include <boost/preprocessor/comma.hpp>
27#include <type_traits>
28
29namespace Trinity::Asio
30{
35template <typename CompletionToken>
37{
38public:
39 // First dummy argument is used to prevent the "default" constructor from being used for implicit conversions
40 constexpr AsExpected(std::type_identity<void> = {}, CompletionToken token = {})
41 : token_(std::forward<CompletionToken>(token))
42 {
43 }
44
45 template <typename T> requires (!std::same_as<T, AsExpected>)
46 constexpr explicit AsExpected(T&& completion_token)
47 : token_(std::forward<T>(completion_token))
48 {
49 }
50
53 template <typename InnerExecutor>
54 struct executor_with_default : InnerExecutor
55 {
58
60 template <typename InnerExecutor1>
61 executor_with_default(InnerExecutor1 const& ex,
62 std::enable_if_t<
63 std::conditional_t<
64 !std::is_same_v<InnerExecutor1, executor_with_default>,
65 std::is_convertible<InnerExecutor1, InnerExecutor>,
66 std::false_type
67 >::value,
68 int
69 > = 0) noexcept
70 : InnerExecutor(ex)
71 {
72 }
73 };
74
77 template <typename T>
78 using as_default_on_t = typename T::template rebind_executor<executor_with_default<typename T::executor_type>>::other;
79
82 template <typename T>
83 static auto as_default_on(T&& object)
84 {
85 return as_default_on_t<std::decay_t<T>>(static_cast<T&&>(object));
86 }
87
88 CompletionToken token_;
89};
90
92{
95 template <typename CompletionToken>
96 [[nodiscard]] inline constexpr AsExpected<std::decay_t<CompletionToken>> operator()(CompletionToken&& completion_token) const
97 {
98 return AsExpected<std::decay_t<CompletionToken>>(static_cast<CompletionToken&&>(completion_token));
99 }
100};
101
109inline constexpr AsExpectedFn as_expected;
110
111namespace Impl
112{
113template <typename T>
114concept CompletionTokenError = std::same_as<std::remove_cvref_t<T>, boost::system::error_code>
115 || std::same_as<std::remove_cvref_t<T>, std::exception_ptr>;
116
117template <typename Handler>
119{
120public:
121 typedef void result_type;
122
123 template <typename CompletionToken>
124 AsExpectedHandler(AsExpected<CompletionToken> e) : handler_(static_cast<CompletionToken&&>(e.token_)) { }
125
126 template <typename RedirectedHandler> requires (!std::same_as<RedirectedHandler, AsExpectedHandler>)
127 AsExpectedHandler(RedirectedHandler&& h) : handler_(std::forward<RedirectedHandler>(h)) { }
128
129 template <CompletionTokenError Error>
130 inline void operator()(Error&& e)
131 {
132 using return_type = boost::outcome_v2::result<void, std::remove_cvref_t<Error>>;
133
134 if (e)
135 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::failure(std::forward<Error>(e))));
136 else
137 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::success()));
138 }
139
140 template <CompletionTokenError Error, typename Arg>
141 inline void operator()(Error&& e, Arg&& value)
142 {
143 using return_type = boost::outcome_v2::result<std::decay_t<Arg>, std::remove_cvref_t<Error>>;
144
145 if (e)
146 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::failure(std::forward<Error>(e))));
147 else
148 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::success(std::forward<Arg>(value))));
149 }
150
151 template <CompletionTokenError Error, typename Arg, typename... Args>
152 inline void operator()(Error&& e, Arg&& first, Args&&... rest)
153 {
154 using return_type = boost::outcome_v2::result<std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>, std::remove_cvref_t<Error>>;
155
156 if (e)
157 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::failure(std::forward<Error>(e))));
158 else
159 static_cast<Handler&&>(handler_)(return_type(boost::outcome_v2::success(std::make_tuple(std::forward<Arg>(first), std::forward<Args>(rest)...))));
160 }
161
162 Handler handler_;
163};
164
165template <typename Handler>
167{
168 using boost::asio::asio_handler_is_continuation;
169 return asio_handler_is_continuation(std::addressof(this_handler->handler_));
170}
171
172template <typename Signature>
174
175#define STAMP_AS_EXPECTED_SIGNATURE(qualifier) \
176 template <typename R, CompletionTokenError Error> \
177 struct AsExpectedSignature<R(Error) qualifier> \
178 { \
179 using type = R(boost::outcome_v2::result<void, std::remove_cvref_t<Error>>) qualifier; \
180 }; \
181 template <typename R, CompletionTokenError Error, typename Arg> \
182 struct AsExpectedSignature<R(Error, Arg) qualifier> \
183 { \
184 using type = R(boost::outcome_v2::result<std::decay_t<Arg>, std::remove_cvref_t<Error>>) qualifier; \
185 }; \
186 template <typename R, CompletionTokenError Error, typename Arg, typename... Args> \
187 struct AsExpectedSignature<R(Error, Arg, Args...) qualifier> \
188 { \
189 using type = R(boost::outcome_v2::result<std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>, std::remove_cvref_t<Error>>) qualifier; \
190 };
191
197STAMP_AS_EXPECTED_SIGNATURE(&& noexcept);
198
199#undef STAMP_AS_EXPECTED_SIGNATURE
200
201} // namespace Impl
202}
203
204namespace boost::asio
205{
206#if BOOST_VERSION >= 107700
207template <typename CompletionToken, typename... Signatures>
208class async_result<Trinity::Asio::AsExpected<CompletionToken>, Signatures...> : async_result<CompletionToken, typename Trinity::Asio::Impl::AsExpectedSignature<Signatures>::type...>
209{
210 template <typename Initiation>
211 struct init_wrapper
212 {
213 explicit init_wrapper(Initiation const& initiation) : initiation_(initiation) { }
214 explicit init_wrapper(Initiation&& initiation) : initiation_(std::move(initiation)) { }
215
216 template <typename Handler, typename... Args>
217 inline void operator()(Handler&& handler, Args&&... args) &&
218 {
219 static_cast<Initiation&&>(initiation_)(Trinity::Asio::Impl::AsExpectedHandler<std::decay_t<Handler>>(std::forward<Handler>(handler)), std::forward<Args>(args)...);
220 }
221
222 template <typename Handler, typename... Args>
223 inline void operator()(Handler&& handler, Args&&... args) const &
224 {
225 static_cast<Initiation const&>(initiation_)(Trinity::Asio::Impl::AsExpectedHandler<std::decay_t<Handler>>(std::forward<Handler>(handler)), std::forward<Args>(args)...);
226 }
227
228 Initiation initiation_;
229 };
230
231public:
232 template <typename Initiation, typename RawCompletionToken, typename... Args>
233 static inline auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
234 {
235 return async_initiate<
236 std::conditional_t<
237 is_const<remove_reference_t<RawCompletionToken>>::value,
238 CompletionToken const, CompletionToken>,
240 init_wrapper<std::decay_t<Initiation>>(
241 std::forward<Initiation>(initiation)),
242 token.token_, std::forward<Args>(args)...);
243 }
244};
245
246#if BOOST_VERSION >= 108600
247#define TRINITY_BOOST_ASIO_ASSOCIATOR_SFINAE_PARAM(param) param
248#else
249#define TRINITY_BOOST_ASIO_ASSOCIATOR_SFINAE_PARAM(param)
250#endif
251
252template <template <typename, typename> class Associator, typename Handler, typename DefaultCandidate TRINITY_BOOST_ASIO_ASSOCIATOR_SFINAE_PARAM(BOOST_PP_COMMA() typename _)>
253struct associator;
254
255template <template <typename, typename> class Associator, typename Handler, typename DefaultCandidate>
256struct associator<Associator, Trinity::Asio::Impl::AsExpectedHandler<Handler>, DefaultCandidate TRINITY_BOOST_ASIO_ASSOCIATOR_SFINAE_PARAM(BOOST_PP_COMMA() void)> : Associator<Handler, DefaultCandidate>
257{
258 static inline auto get(Trinity::Asio::Impl::AsExpectedHandler<Handler> const& h) noexcept
259 {
260 return Associator<Handler, DefaultCandidate>::get(h.handler_);
261 }
262
263 static inline auto get(Trinity::Asio::Impl::AsExpectedHandler<Handler> const& h, DefaultCandidate const& c) noexcept
264 {
265 return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
266 }
267};
268
269#undef TRINITY_BOOST_ASIO_ASSOCIATOR_SFINAE_PARAM
270
271template <typename... Signatures>
272class async_result<Trinity::Asio::AsExpectedFn, Signatures...>
273{
274public:
275 template <typename Initiation, typename RawCompletionToken, typename... Args>
276 static inline auto initiate(Initiation&& initiation, RawCompletionToken&&, Args&&... args)
277 {
278 return async_initiate<Signatures...>(
279 std::forward<Initiation>(initiation),
281 default_completion_token_t<associated_executor_t<Initiation>>>{},
282 std::forward<Args>(args)...);
283 }
284};
285#else
286template <typename CompletionToken, typename Signature>
287class async_result<Trinity::Asio::AsExpected<CompletionToken>, Signature> : async_result<CompletionToken, typename Trinity::Asio::Impl::AsExpectedSignature<Signature>::type>
288{
289 template <typename Initiation>
290 struct init_wrapper
291 {
292 explicit init_wrapper(Initiation const& initiation) : initiation_(initiation) { }
293 explicit init_wrapper(Initiation&& initiation) : initiation_(std::move(initiation)) { }
294
295 template <typename Handler, typename... Args>
296 inline void operator()(Handler&& handler, Args&&... args) &&
297 {
298 static_cast<Initiation&&>(initiation_)(Trinity::Asio::Impl::AsExpectedHandler<std::decay_t<Handler>>(std::forward<Handler>(handler)), std::forward<Args>(args)...);
299 }
300
301 template <typename Handler, typename... Args>
302 inline void operator()(Handler&& handler, Args&&... args) const &
303 {
304 static_cast<Initiation const&>(initiation_)(Trinity::Asio::Impl::AsExpectedHandler<std::decay_t<Handler>>(std::forward<Handler>(handler)), std::forward<Args>(args)...);
305 }
306
307 Initiation initiation_;
308 };
309
310public:
311 template <typename Initiation, typename RawCompletionToken, typename... Args>
312 static inline auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
313 {
314 return async_initiate<
315 std::conditional_t<
316 is_const<remove_reference_t<RawCompletionToken>>::value,
317 CompletionToken const, CompletionToken>,
319 init_wrapper<std::decay_t<Initiation>>(
320 std::forward<Initiation>(initiation)),
321 token.token_, std::forward<Args>(args)...);
322 }
323};
324#endif
325} // namespace boost::asio
326
327#endif // TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H
#define STAMP_AS_EXPECTED_SIGNATURE(qualifier)
std::pair< uint32, ObjectGuid > Signature
Definition PetitionMgr.h:50
constexpr AsExpected(std::type_identity< void >={}, CompletionToken token={})
typename T::template rebind_executor< executor_with_default< typename T::executor_type > >::other as_default_on_t
constexpr AsExpected(T &&completion_token)
static auto as_default_on(T &&object)
AsExpectedHandler(AsExpected< CompletionToken > e)
void operator()(Error &&e, Arg &&first, Args &&... rest)
static auto initiate(Initiation &&initiation, RawCompletionToken &&token, Args &&... args)
bool asio_handler_is_continuation(AsExpectedHandler< Handler > *this_handler)
constexpr AsExpectedFn as_expected
void Error(char const *file, int line, char const *function, char const *message) noexcept
Definition Errors.cpp:121
STL namespace.
constexpr AsExpected< std::decay_t< CompletionToken > > operator()(CompletionToken &&completion_token) const
executor_with_default(InnerExecutor1 const &ex, std::enable_if_t< std::conditional_t< !std::is_same_v< InnerExecutor1, executor_with_default >, std::is_convertible< InnerExecutor1, InnerExecutor >, std::false_type >::value, int >=0) noexcept
Construct the adapted executor from the inner executor type.
AsExpected default_completion_token_type
Specify AsExpected as the default completion token type.