#ifndef ASYNC_MQTT5_ASYNC_TRAITS_HPP #define ASYNC_MQTT5_ASYNC_TRAITS_HPP #include #include #include #include #include #include #include #include #include namespace async_mqtt5 { namespace asio = boost::asio; template struct tls_handshake_type {}; template void assign_tls_sni(const authority_path& ap, TlsContext& ctx, TlsStream& s); namespace detail { template using tracking_type = std::decay_t< typename asio::prefer_result< asio::associated_executor_t, asio::execution::outstanding_work_t::tracked_t >::type >; template tracking_type tracking_executor(const Handler& handler, const DfltExecutor& ex) { return asio::prefer( asio::get_associated_executor(handler, ex), asio::execution::outstanding_work.tracked ); } template using async_write_sig = decltype( std::declval().async_write(std::declval()...) ); constexpr auto write_handler_t = [](error_code, size_t) {}; template constexpr bool has_async_write = boost::is_detected< async_write_sig, T, B, decltype(write_handler_t) >::value; constexpr auto handshake_handler_t = [](error_code) {}; template using tls_handshake_t = typename T::handshake_type; template using tls_handshake_type_of = boost::detected_or_t; template using async_tls_handshake_sig = decltype( std::declval().async_handshake(std::declval()...) ); template constexpr bool has_tls_handshake = boost::is_detected< async_tls_handshake_sig, T, tls_handshake_type_of, decltype(handshake_handler_t) >::value; template using async_ws_handshake_sig = decltype( std::declval().async_handshake(std::declval()...) ); template constexpr bool has_ws_handshake = boost::is_detected< async_ws_handshake_sig, T, std::string_view, std::string_view, decltype(handshake_handler_t) >::value; template using tls_context_sig = decltype( std::declval().tls_context() ); template constexpr bool has_tls_context = boost::is_detected< tls_context_sig, T >::value; template using next_layer_sig = decltype( std::declval().next_layer() ); template constexpr bool has_next_layer = boost::is_detected< next_layer_sig, T >::value; template struct next_layer_type { using type = T; }; template struct next_layer_type< T, std::enable_if_t> > { using type = typename std::remove_reference_t::next_layer_type; }; template typename next_layer_type>>::type& next_layer(T&& a) { return a; } template typename next_layer_type>>::type& next_layer(T&& a) { return a.next_layer(); } template using lowest_layer_type = typename boost::beast::lowest_layer_type; template lowest_layer_type& lowest_layer(S&& a) { return boost::beast::get_lowest_layer(std::forward(a)); } template struct has_tls_layer_impl : std::false_type {}; template struct has_tls_layer_impl< T, std::enable_if_t> > : std::true_type {}; template struct has_tls_layer_impl< T, std::enable_if_t && has_next_layer> > : has_tls_layer_impl< boost::remove_cv_ref_t().next_layer())> > {}; template constexpr bool has_tls_layer = has_tls_layer_impl< boost::remove_cv_ref_t >::value; template < typename Stream, typename ConstBufferSequence, typename CompletionToken > decltype(auto) async_write( Stream& stream, const ConstBufferSequence& buff, CompletionToken&& token ) { if constexpr (has_async_write) return stream.async_write( buff, std::forward(token) ); else return asio::async_write( stream, buff, std::forward(token) ); } template void setup_tls_sni(const authority_path& ap, TlsContext& ctx, Stream& s) { if constexpr (has_tls_handshake) assign_tls_sni(ap, ctx, s); else if constexpr (has_next_layer) setup_tls_sni(ap, ctx, next_layer(s)); } } // end namespace detail } // end namespace async_mqtt5 #endif // !ASYNC_MQTT5_ASYNC_TRAITS_HPP