#ifndef ASYNC_MQTT5_ANY_AUTHENTICATOR #define ASYNC_MQTT5_ANY_AUTHENTICATOR #include #include #include #include #include namespace async_mqtt5 { namespace asio = boost::asio; using error_code = boost::system::error_code; namespace detail { using auth_handler_type = asio::any_completion_handler< void (error_code ec, std::string auth_data) >; template using async_auth_sig = decltype( std::declval().async_auth(std::declval()...) ); template using method_sig = decltype( std::declval().method() ); template constexpr bool is_authenticator = boost::is_detected< async_auth_sig, T, auth_step_e, std::string, auth_handler_type >::value && boost::is_detected_convertible_v; class auth_fun_base { using auth_func = void(*)( auth_step_e, std::string, auth_handler_type, auth_fun_base* ); auth_func _auth_func; public: auth_fun_base(auth_func f) : _auth_func(f) {} ~auth_fun_base() = default; void async_auth( auth_step_e step, std::string data, auth_handler_type auth_handler ) { _auth_func(step, std::move(data), std::move(auth_handler), this); } }; template < typename Authenticator, typename = std::enable_if_t> > class auth_fun : public auth_fun_base { Authenticator _authenticator; public: auth_fun(Authenticator authenticator) : auth_fun_base(&async_auth), _authenticator(std::forward(authenticator)) {} static void async_auth( auth_step_e step, std::string data, auth_handler_type auth_handler, auth_fun_base* base_ptr ) { auto auth_fun_ptr = static_cast(base_ptr); auth_fun_ptr->_authenticator.async_auth( step, std::move(data), std::move(auth_handler) ); } }; } // end namespace detail class any_authenticator { std::string _method; std::unique_ptr _auth_fun; public: any_authenticator() = default; template < typename Authenticator, std::enable_if_t, bool> = true > any_authenticator(Authenticator&& a) : _method(a.method()), _auth_fun( new detail::auth_fun( std::forward(a) ) ) {} std::string_view method() const { return _method; } template decltype(auto) async_auth( auth_step_e step, std::string data, CompletionToken&& token ) { using Signature = void (error_code, std::string); auto initiation = []( auto handler, any_authenticator& self, auth_step_e step, std::string data ) { self._auth_fun->async_auth( step, std::move(data), std::move(handler) ); }; return asio::async_initiate( initiation, token, std::ref(*this), step, std::move(data) ); } }; } // end namespace async_mqtt5 #endif // !ASYNC_MQTT5_ANY_AUTHENTICATOR