#include "network_functions.hpp" #include #include #include using namespace boost::mysql::test; using boost::mysql::tcp_prepared_statement; using boost::mysql::tcp_resultset; using boost::mysql::tcp_connection; using boost::mysql::error_info; using boost::mysql::error_code; using boost::mysql::detail::make_error_code; using boost::mysql::errc; using boost::mysql::value; using boost::mysql::row; using boost::mysql::owning_row; using boost::asio::yield_context; using boost::asio::use_future; namespace { class sync_errc : public network_functions { template static auto impl(Callable&& cb) { using R = decltype(cb(std::declval(), std::declval())); network_result res (make_error_code(errc::no), error_info("errc info not cleared correctly")); res.value = cb(res.err, *res.info); return res; } public: const char* name() const override { return "sync_errc"; } network_result handshake( tcp_connection& conn, const boost::mysql::connection_params& params ) override { return impl([&](error_code& code, error_info& info) { conn.handshake(params, code, info); return no_result(); }); } network_result query( tcp_connection& conn, std::string_view query ) override { return impl([&](error_code& code, error_info& info) { return conn.query(query, code, info); }); } network_result prepare_statement( tcp_connection& conn, std::string_view statement ) override { return impl([&conn, statement](error_code& err, error_info& info) { return conn.prepare_statement(statement, err, info); }); } network_result execute_statement( tcp_prepared_statement& stmt, value_list_it params_first, value_list_it params_last ) override { return impl([=, &stmt](error_code& err, error_info& info) { return stmt.execute(params_first, params_last, err, info); }); } network_result execute_statement( tcp_prepared_statement& stmt, const std::vector& values ) override { return impl([&stmt, &values](error_code& err, error_info& info) { return stmt.execute(values, err, info); }); } network_result close_statement( tcp_prepared_statement& stmt ) override { return impl([&](error_code& code, error_info& info) { stmt.close(code, info); return no_result(); }); } network_result fetch_one( tcp_resultset& r ) override { return impl([&](error_code& code, error_info& info) { return r.fetch_one(code, info); }); } network_result> fetch_many( tcp_resultset& r, std::size_t count ) override { return impl([&](error_code& code, error_info& info) { return r.fetch_many(count, code, info); }); } network_result> fetch_all( tcp_resultset& r ) override { return impl([&](error_code& code, error_info& info) { return r.fetch_all(code, info); }); } }; class sync_exc : public network_functions { template static auto impl(Callable&& cb) { using R = decltype(cb()); network_result res; try { res.value = cb(); } catch (const boost::system::system_error& err) { res.err = err.code(); res.info = error_info(err.what()); } return res; } public: const char* name() const override { return "sync_exc"; } network_result handshake( tcp_connection& conn, const boost::mysql::connection_params& params ) override { return impl([&] { conn.handshake(params); return no_result(); }); } network_result query( tcp_connection& conn, std::string_view query ) override { return impl([&] { return conn.query(query); }); } network_result prepare_statement( tcp_connection& conn, std::string_view statement ) override { return impl([&conn, statement] { return conn.prepare_statement(statement); }); } network_result execute_statement( tcp_prepared_statement& stmt, value_list_it params_first, value_list_it params_last ) override { return impl([&]{ return stmt.execute(params_first, params_last); }); } network_result execute_statement( tcp_prepared_statement& stmt, const std::vector& values ) override { return impl([&stmt, &values] { return stmt.execute(values); }); } network_result close_statement( tcp_prepared_statement& stmt ) override { return impl([&] { stmt.close(); return no_result(); }); } network_result fetch_one( tcp_resultset& r ) override { return impl([&] { return r.fetch_one(); }); } network_result> fetch_many( tcp_resultset& r, std::size_t count ) override { return impl([&] { return r.fetch_many(count); }); } network_result> fetch_all( tcp_resultset& r ) override { return impl([&] { return r.fetch_all(); }); } }; class async_callback : public network_functions { template static network_result impl(Callable&& cb) { std::promise> prom; cb([&prom](error_code code, auto retval) { prom.set_value(network_result( code, std::move(retval.error()), std::move(retval.get()) )); }); return prom.get_future().get(); } template static network_result impl_no_result(Callable&& cb) { std::promise> prom; cb([&prom](error_code code, error_info info) { prom.set_value(network_result(code, std::move(info))); }); return prom.get_future().get(); } public: const char* name() const override { return "async_callback"; } network_result handshake( tcp_connection& conn, const boost::mysql::connection_params& params ) override { return impl_no_result([&](auto&& token) { return conn.async_handshake(params, std::forward(token)); }); } network_result query( tcp_connection& conn, std::string_view query ) override { return impl([&](auto&& token) { return conn.async_query(query, std::forward(token)); }); } network_result prepare_statement( tcp_connection& conn, std::string_view statement ) override { return impl([&conn, statement](auto&& token) { return conn.async_prepare_statement(statement, std::forward(token)); }); } network_result execute_statement( tcp_prepared_statement& stmt, value_list_it params_first, value_list_it params_last ) override { return impl([&](auto&& token) { return stmt.async_execute(params_first, params_last, std::forward(token)); }); } network_result execute_statement( tcp_prepared_statement& stmt, const std::vector& values ) override { return impl([&](auto&& token) { return stmt.async_execute(values, std::forward(token)); }); } network_result close_statement( tcp_prepared_statement& stmt ) override { return impl_no_result([&](auto&& token) { return stmt.async_close(std::forward(token)); }); } network_result fetch_one( tcp_resultset& r ) override { return impl([&](auto&& token) { return r.async_fetch_one(std::forward(token)); }); } network_result> fetch_many( tcp_resultset& r, std::size_t count ) override { return impl>([&](auto&& token) { return r.async_fetch_many(count, std::forward(token)); }); } network_result> fetch_all( tcp_resultset& r ) override { return impl>([&](auto&& token) { return r.async_fetch_all(std::forward(token)); }); } }; class async_coroutine : public network_functions { template static auto impl(IoObj& obj, Callable&& cb) { using R = typename decltype(cb(std::declval()))::value_type; std::promise> prom; boost::asio::spawn(obj.next_layer().get_executor(), [&](yield_context yield) { error_code ec; auto result = cb(yield[ec]); prom.set_value(network_result( ec, std::move(result.error()), std::move(result.get()) )); }); return prom.get_future().get(); } template static network_result impl_no_result(IoObj& obj, Callable&& cb) { auto executor = obj.next_layer().get_executor(); std::promise> prom; boost::asio::spawn(executor, [&](yield_context yield) { error_code ec; error_info info = cb(yield[ec]); prom.set_value(network_result(ec, std::move(info))); }); return prom.get_future().get(); } public: const char* name() const override { return "async_coroutine"; } network_result handshake( tcp_connection& conn, const boost::mysql::connection_params& params ) override { return impl_no_result(conn, [&](yield_context yield) { return conn.async_handshake(params, yield); }); } network_result query( tcp_connection& conn, std::string_view query ) override { return impl(conn, [&](yield_context yield) { return conn.async_query(query, yield); }); } network_result prepare_statement( tcp_connection& conn, std::string_view statement ) override { return impl(conn, [&](yield_context yield) { return conn.async_prepare_statement(statement, yield); }); } network_result execute_statement( tcp_prepared_statement& stmt, value_list_it params_first, value_list_it params_last ) override { return impl(stmt, [&](yield_context yield) { return stmt.async_execute(params_first, params_last, yield); }); } network_result execute_statement( tcp_prepared_statement& stmt, const std::vector& values ) override { return impl(stmt, [&](yield_context yield) { return stmt.async_execute(values, yield); }); } network_result close_statement( tcp_prepared_statement& stmt ) override { return impl_no_result(stmt, [&](yield_context yield) { return stmt.async_close(yield); }); } network_result fetch_one( tcp_resultset& r ) override { return impl(r, [&](yield_context yield) { return r.async_fetch_one(yield); }); } network_result> fetch_many( tcp_resultset& r, std::size_t count ) override { return impl(r, [&](yield_context yield) { return r.async_fetch_many(count, yield); }); } network_result> fetch_all( tcp_resultset& r ) override { return impl(r, [&](yield_context yield) { return r.async_fetch_all(yield); }); } }; class async_future : public network_functions { template static auto impl(Callable&& cb) { // Callable returns a future> using R = typename decltype(cb().get())::value_type; std::future> fut = cb(); try { auto result = fut.get(); return network_result( error_code(), std::move(result.error()), // the returned error_info should be empty std::move(result.get()) ); } catch (const boost::system::system_error& err) { // error_info is not available here, so we skip validation return network_result(err.code()); } } template static network_result impl_no_result(Callable&& cb) { std::future fut = cb(); try { // This should be returning an empty error_info, so we validate that return network_result(error_code(), fut.get()); } catch (const boost::system::system_error& err) { return network_result(err.code()); } } public: const char* name() const override { return "async_future"; } network_result handshake( tcp_connection& conn, const boost::mysql::connection_params& params ) override { return impl_no_result([&] { return conn.async_handshake(params, use_future); }); } network_result query( tcp_connection& conn, std::string_view query ) override { return impl([&] { return conn.async_query(query, use_future); }); } network_result prepare_statement( tcp_connection& conn, std::string_view statement ) override { return impl([&]{ return conn.async_prepare_statement(statement, use_future); }); } network_result execute_statement( tcp_prepared_statement& stmt, value_list_it params_first, value_list_it params_last ) override { return impl([&]{ return stmt.async_execute(params_first, params_last, use_future); }); } network_result execute_statement( tcp_prepared_statement& stmt, const std::vector& values ) override { return impl([&] { return stmt.async_execute(values, use_future); }); } network_result close_statement( tcp_prepared_statement& stmt ) override { return impl_no_result([&] { return stmt.async_close(use_future); }); } network_result fetch_one( tcp_resultset& r ) override { return impl([&] { return r.async_fetch_one(use_future); }); } network_result> fetch_many( tcp_resultset& r, std::size_t count ) override { return impl([&] { return r.async_fetch_many(count, use_future); }); } network_result> fetch_all( tcp_resultset& r ) override { return impl([&] { return r.async_fetch_all(use_future); }); } }; // Global objects to be exposed sync_errc sync_errc_obj; sync_exc sync_exc_obj; async_callback async_callback_obj; async_coroutine async_coroutine_obj; async_future async_future_obj; } // Visible stuff boost::mysql::test::network_functions* boost::mysql::test::sync_errc_network_functions = &sync_errc_obj; boost::mysql::test::network_functions* boost::mysql::test::sync_exc_network_functions = &sync_exc_obj; boost::mysql::test::network_functions* boost::mysql::test::async_callback_network_functions = &async_callback_obj; boost::mysql::test::network_functions* boost::mysql::test::async_coroutine_network_functions = &async_coroutine_obj; boost::mysql::test::network_functions* boost::mysql::test::async_future_network_functions = &async_future_obj;