/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H
#define TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H
#include
#include
#include
#include
#include
#include
namespace Trinity::Asio
{
/// The AsExpected class is used to indicate that any arguments to the
/// completion handler should be combined and passed as a single @c boost::outcome_v2::result argument.
/// The arguments are first moved into a @c boost::outcome_v2::result and that is then
/// passed to the completion handler.
template
class AsExpected
{
public:
// First dummy argument is used to prevent the "default" constructor from being used for implicit conversions
constexpr AsExpected(std::type_identity = {}, CompletionToken token = {})
: token_(std::forward(token))
{
}
template requires (!std::same_as)
constexpr explicit AsExpected(T&& completion_token)
: token_(std::forward(completion_token))
{
}
/// Adapts an executor to add the @c AsExpected completion token as the
/// default.
template
struct executor_with_default : InnerExecutor
{
/// Specify @c AsExpected as the default completion token type.
typedef AsExpected default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template
executor_with_default(InnerExecutor1 const& ex,
std::enable_if_t<
std::conditional_t<
!std::is_same_v,
std::is_convertible,
std::false_type
>::value,
int
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c AsExpected as its
/// default completion token type.
template
using as_default_on_t = typename T::template rebind_executor>::other;
/// Function helper to adapt an I/O object to use @c AsExpected as its
/// default completion token type.
template
static auto as_default_on(T&& object)
{
return as_default_on_t>(static_cast(object));
}
CompletionToken token_;
};
struct AsExpectedFn
{
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single @c boost::outcome_v2::result argument.
template
[[nodiscard]] inline constexpr AsExpected> operator()(CompletionToken&& completion_token) const
{
return AsExpected>(static_cast(completion_token));
}
};
/// A function object that adapts a @ref completion_token to specify that the
/// completion handler arguments should be combined into a single @c boost::outcome_v2::result
/// argument.
///
/// May also be used directly as a completion token, in which case it adapts the
/// asynchronous operation's default completion token (or @ref boost::asio::deferred
/// if no default is available).
inline constexpr AsExpectedFn as_expected;
namespace Impl
{
template
concept CompletionTokenError = std::same_as, boost::system::error_code>
|| std::same_as, std::exception_ptr>;
template
class AsExpectedHandler
{
public:
typedef void result_type;
template
AsExpectedHandler(AsExpected e) : handler_(static_cast(e.token_)) { }
template requires (!std::same_as)
AsExpectedHandler(RedirectedHandler&& h) : handler_(std::forward(h)) { }
template
inline void operator()(Error&& e)
{
using return_type = boost::outcome_v2::result>;
if (e)
static_cast(handler_)(return_type(boost::outcome_v2::failure(std::forward(e))));
else
static_cast(handler_)(return_type(boost::outcome_v2::success()));
}
template
inline void operator()(Error&& e, Arg&& value)
{
using return_type = boost::outcome_v2::result, std::remove_cvref_t>;
if (e)
static_cast(handler_)(return_type(boost::outcome_v2::failure(std::forward(e))));
else
static_cast(handler_)(return_type(boost::outcome_v2::success(std::forward(value))));
}
template
inline void operator()(Error&& e, Arg&& first, Args&&... rest)
{
using return_type = boost::outcome_v2::result, std::decay_t...>, std::remove_cvref_t>;
if (e)
static_cast(handler_)(return_type(boost::outcome_v2::failure(std::forward(e))));
else
static_cast(handler_)(return_type(boost::outcome_v2::success(std::make_tuple(std::forward(first), std::forward(rest)...))));
}
Handler handler_;
};
template
inline bool asio_handler_is_continuation(AsExpectedHandler* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(this_handler->handler_);
}
template
struct AsExpectedSignature;
#define STAMP_AS_EXPECTED_SIGNATURE(qualifier) \
template \
struct AsExpectedSignature \
{ \
using type = R(boost::outcome_v2::result>) qualifier; \
}; \
template \
struct AsExpectedSignature \
{ \
using type = R(boost::outcome_v2::result, std::remove_cvref_t>) qualifier; \
}; \
template \
struct AsExpectedSignature \
{ \
using type = R(boost::outcome_v2::result, std::decay_t...>, std::remove_cvref_t>) qualifier; \
};
STAMP_AS_EXPECTED_SIGNATURE(BOOST_PP_EMPTY());
STAMP_AS_EXPECTED_SIGNATURE(&);
STAMP_AS_EXPECTED_SIGNATURE(&&);
STAMP_AS_EXPECTED_SIGNATURE(noexcept);
STAMP_AS_EXPECTED_SIGNATURE(& noexcept);
STAMP_AS_EXPECTED_SIGNATURE(&& noexcept);
} // namespace Impl
}
namespace boost::asio
{
#if BOOST_VERSION >= 107700
template
class async_result, Signatures...> : async_result::type...>
{
template
struct init_wrapper
{
explicit init_wrapper(Initiation const& initiation) : initiation_(initiation) { }
explicit init_wrapper(Initiation&& initiation) : initiation_(std::move(initiation)) { }
template
inline void operator()(Handler&& handler, Args&&... args) &&
{
static_cast(initiation_)(Trinity::Asio::Impl::AsExpectedHandler>(std::forward(handler)), std::forward(args)...);
}
template
inline void operator()(Handler&& handler, Args&&... args) const &
{
static_cast(initiation_)(Trinity::Asio::Impl::AsExpectedHandler>(std::forward(handler)), std::forward(args)...);
}
Initiation initiation_;
};
public:
template
static inline auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
{
return async_initiate<
conditional_t<
is_const>::value,
CompletionToken const, CompletionToken>,
typename Trinity::Asio::Impl::AsExpectedSignature::type...>(
init_wrapper>(
std::forward(initiation)),
token.token_, std::forward(args)...);
}
};
template class Associator, typename Handler, typename DefaultCandidate, typename _>
struct associator;
template class Associator, typename Handler, typename DefaultCandidate>
struct associator, DefaultCandidate, void> : Associator
{
static inline auto get(Trinity::Asio::Impl::AsExpectedHandler const& h) noexcept
{
return Associator::get(h.handler_);
}
static inline auto get(Trinity::Asio::Impl::AsExpectedHandler const& h, DefaultCandidate const& c) noexcept
{
return Associator::get(h.handler_, c);
}
};
template
class async_result
{
public:
template
static inline auto initiate(Initiation&& initiation, RawCompletionToken&&, Args&&... args)
{
return async_initiate(
std::forward(initiation),
Trinity::Asio::AsExpected<
default_completion_token_t>>{},
std::forward(args)...);
}
};
#else
template
class async_result, Signature> : async_result::type>
{
template
struct init_wrapper
{
explicit init_wrapper(Initiation const& initiation) : initiation_(initiation) { }
explicit init_wrapper(Initiation&& initiation) : initiation_(std::move(initiation)) { }
template
inline void operator()(Handler&& handler, Args&&... args) &&
{
static_cast(initiation_)(Trinity::Asio::Impl::AsExpectedHandler>(std::forward(handler)), std::forward(args)...);
}
template
inline void operator()(Handler&& handler, Args&&... args) const &
{
static_cast(initiation_)(Trinity::Asio::Impl::AsExpectedHandler>(std::forward(handler)), std::forward(args)...);
}
Initiation initiation_;
};
public:
template
static inline auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
{
return async_initiate<
conditional_t<
is_const>::value,
CompletionToken const, CompletionToken>,
typename Trinity::Asio::Impl::AsExpectedSignature::type>(
init_wrapper>(
std::forward(initiation)),
token.token_, std::forward(args)...);
}
};
#endif
} // namespace boost::asio
#endif // TRINITYCORE_EXPECTED_COMPLETION_HANDLER_H