/* * 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