File indexing completed on 2025-09-15 08:42:58
0001
0002
0003
0004
0005
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
0047 const diagnostics& diag;
0048
0049
0050 std::shared_ptr<diagnostics> owning_diag;
0051 };
0052
0053
0054
0055
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
0101
0102
0103
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
0113 template <class Handler, class... Args>
0114 void operator()(Handler&& handler, Args&&... args) &&
0115 {
0116
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
0121
0122 static_assert(
0123 pos < mp11::mp_size<types>::value,
0124 "with_diagnostics only works with Boost.MySQL async functions"
0125 );
0126
0127
0128 diagnostics*& diag = std::get<pos>(std::tuple<Args&...>{args...});
0129
0130
0131
0132 std::shared_ptr<diagnostics> owning_diag;
0133 if (!diag)
0134 {
0135
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
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
0156
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
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
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 }
0227 }
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 }
0241 }
0242
0243 #endif