Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:42:58

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_WITH_DIAGNOSTICS_HPP
0009 #define BOOST_MYSQL_IMPL_WITH_DIAGNOSTICS_HPP
0010 
0011 #pragma once
0012 
0013 #include <boost/mysql/diagnostics.hpp>
0014 #include <boost/mysql/error_code.hpp>
0015 #include <boost/mysql/error_with_diagnostics.hpp>
0016 #include <boost/mysql/with_diagnostics.hpp>
0017 
0018 #include <boost/mysql/detail/intermediate_handler.hpp>
0019 
0020 #include <boost/asio/associated_allocator.hpp>
0021 #include <boost/asio/async_result.hpp>
0022 #include <boost/mp11/algorithm.hpp>
0023 #include <boost/mp11/list.hpp>
0024 
0025 #include <cstddef>
0026 #include <exception>
0027 #include <memory>
0028 #include <tuple>
0029 #include <type_traits>
0030 
0031 namespace boost {
0032 namespace mysql {
0033 namespace detail {
0034 
0035 struct with_diag_handler_fn
0036 {
0037     template <class Handler, class... Args>
0038     void operator()(Handler&& handler, error_code ec, Args&&... args)
0039     {
0040         std::exception_ptr exc = ec ? std::make_exception_ptr(error_with_diagnostics(ec, diag))
0041                                     : std::exception_ptr();
0042         owning_diag.reset();
0043         std::move(handler)(std::move(exc), std::forward<Args>(args)...);
0044     }
0045 
0046     // The diagnostics to use, taken from initiation
0047     const diagnostics& diag;
0048 
0049     // Keep alive any allocated diagnostics
0050     std::shared_ptr<diagnostics> owning_diag;
0051 };
0052 
0053 // By default, don't modify the signature.
0054 // This makes asio::as_tuple(with_diagnostics(X)) equivalent
0055 // to asio::as_tuple(X).
0056 template <typename Signature>
0057 struct with_diag_signature
0058 {
0059     using type = Signature;
0060 };
0061 
0062 template <typename R, typename... Args>
0063 struct with_diag_signature<R(error_code, Args...)>
0064 {
0065     using type = R(std::exception_ptr, Args...);
0066 };
0067 
0068 template <typename R, typename... Args>
0069 struct with_diag_signature<R(error_code, Args...)&>
0070 {
0071     using type = R(std::exception_ptr, Args...) &;
0072 };
0073 
0074 template <typename R, typename... Args>
0075 struct with_diag_signature<R(error_code, Args...) &&>
0076 {
0077     using type = R(std::exception_ptr, Args...) &&;
0078 };
0079 
0080 #if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
0081 
0082 template <typename R, typename... Args>
0083 struct with_diag_signature<R(error_code, Args...) noexcept>
0084 {
0085     using type = R(std::exception_ptr, Args...) noexcept;
0086 };
0087 
0088 template <typename R, typename... Args>
0089 struct with_diag_signature<R(error_code, Args...) & noexcept>
0090 {
0091     using type = R(std::exception_ptr, Args...) & noexcept;
0092 };
0093 
0094 template <typename R, typename... Args>
0095 struct with_diag_signature<R(error_code, Args...) && noexcept>
0096 {
0097     using type = R(std::exception_ptr, Args...) && noexcept;
0098 };
0099 
0100 #endif  // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
0101 
0102 // Inheriting from Initiation propagates its executor type,
0103 // if any. Required by tokens like asio::cancel_after
0104 template <class Initiation>
0105 struct with_diag_init : public Initiation
0106 {
0107     template <class I>
0108     with_diag_init(I&& i) : Initiation(std::forward<I>(i))
0109     {
0110     }
0111 
0112     // We pass the inner token's initiation as 1st arg
0113     template <class Handler, class... Args>
0114     void operator()(Handler&& handler, Args&&... args) &&
0115     {
0116         // Find the diagnostics object in the list of arguments
0117         using types = mp11::mp_list<typename std::decay<Args>::type...>;
0118         constexpr std::size_t pos = mp11::mp_find<types, diagnostics*>::value;
0119 
0120         // If you're getting an error here, it's because you're trying to use
0121         // with_diagnostics with an async function unrelated to Boost.MySQL.
0122         static_assert(
0123             pos < mp11::mp_size<types>::value,
0124             "with_diagnostics only works with Boost.MySQL async functions"
0125         );
0126 
0127         // Actually get the object
0128         diagnostics*& diag = std::get<pos>(std::tuple<Args&...>{args...});
0129 
0130         // Some functions (e.g. connection_pool) may pass nullptr as diag.
0131         // When using this token, allocate a diagnostics instance and overwrite the passed value
0132         std::shared_ptr<diagnostics> owning_diag;
0133         if (!diag)
0134         {
0135             // The allocator to use
0136             auto base_alloc = asio::get_associated_allocator(handler);
0137             using alloc_type = typename std::allocator_traits<decltype(base_alloc
0138             )>::template rebind_alloc<diagnostics>;
0139 
0140             owning_diag = std::allocate_shared<diagnostics>(alloc_type{std::move(base_alloc)});
0141             diag = owning_diag.get();
0142         }
0143 
0144         // Actually initiate
0145         static_cast<Initiation&&>(*this)(
0146             make_intermediate_handler(
0147                 with_diag_handler_fn{*diag, std::move(owning_diag)},
0148                 std::forward<Handler>(handler)
0149             ),
0150             std::forward<Args>(args)...
0151         );
0152     }
0153 };
0154 
0155 // Did with_diagnostics modify any of the signatures?
0156 // We really support only modifying all or none, and that's enough.
0157 template <class Signature>
0158 using with_diag_has_original_signature = std::
0159     is_same<Signature, typename with_diag_signature<Signature>::type>;
0160 
0161 template <class... Signatures>
0162 using with_diag_has_original_signatures = mp11::
0163     mp_all_of<mp11::mp_list<Signatures...>, with_diag_has_original_signature>;
0164 
0165 template <typename CompletionToken, bool has_original_signatures, typename... Signatures>
0166 struct with_diagnostics_async_result;
0167 
0168 // async_result when the signature was modified
0169 template <typename CompletionToken, typename... Signatures>
0170 struct with_diagnostics_async_result<CompletionToken, false, Signatures...>
0171     : asio::async_result<CompletionToken, typename with_diag_signature<Signatures>::type...>
0172 {
0173     template <class RawCompletionToken>
0174     using maybe_const_token_t = typename std::conditional<
0175         std::is_const<typename std::remove_reference<RawCompletionToken>::type>::value,
0176         const CompletionToken,
0177         CompletionToken>::type;
0178 
0179     template <typename Initiation, typename RawCompletionToken, typename... Args>
0180     static auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
0181         -> decltype(asio::async_initiate<
0182                     maybe_const_token_t<RawCompletionToken>,
0183                     typename with_diag_signature<Signatures>::type...>(
0184             with_diag_init<typename std::decay<Initiation>::type>{std::forward<Initiation>(initiation)},
0185             access::get_impl(token),
0186             std::forward<Args>(args)...
0187         ))
0188     {
0189         return asio::async_initiate<
0190             maybe_const_token_t<RawCompletionToken>,
0191             typename with_diag_signature<Signatures>::type...>(
0192             with_diag_init<typename std::decay<Initiation>::type>{std::forward<Initiation>(initiation)},
0193             access::get_impl(token),
0194             std::forward<Args>(args)...
0195         );
0196     }
0197 };
0198 
0199 // async_result when the signature wasn't modified (pass-through)
0200 template <typename CompletionToken, typename... Signatures>
0201 struct with_diagnostics_async_result<CompletionToken, true, Signatures...>
0202     : asio::async_result<CompletionToken, Signatures...>
0203 {
0204     template <class RawCompletionToken>
0205     using maybe_const_token_t = typename std::conditional<
0206         std::is_const<typename std::remove_reference<RawCompletionToken>::type>::value,
0207         const CompletionToken,
0208         CompletionToken>::type;
0209 
0210     template <typename Initiation, typename RawCompletionToken, typename... Args>
0211     static auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)
0212         -> decltype(asio::async_initiate<maybe_const_token_t<RawCompletionToken>, Signatures...>(
0213             std::forward<Initiation>(initiation),
0214             access::get_impl(token),
0215             std::forward<Args>(args)...
0216         ))
0217     {
0218         return asio::async_initiate<maybe_const_token_t<RawCompletionToken>, Signatures...>(
0219             std::forward<Initiation>(initiation),
0220             access::get_impl(token),
0221             std::forward<Args>(args)...
0222         );
0223     }
0224 };
0225 
0226 }  // namespace detail
0227 }  // namespace mysql
0228 
0229 namespace asio {
0230 
0231 template <typename CompletionToken, typename... Signatures>
0232 struct async_result<mysql::with_diagnostics_t<CompletionToken>, Signatures...>
0233     : mysql::detail::with_diagnostics_async_result<
0234           CompletionToken,
0235           mysql::detail::with_diag_has_original_signatures<Signatures...>::value,
0236           Signatures...>
0237 {
0238 };
0239 
0240 }  // namespace asio
0241 }  // namespace boost
0242 
0243 #endif