// // experimental/awaitable_operators.cpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Disable autolinking for unit tests. #if !defined(BOOST_ALL_NO_LIB) #define BOOST_ALL_NO_LIB 1 #endif // !defined(BOOST_ALL_NO_LIB) // Prevent link dependency on the Boost.System library. #if !defined(BOOST_SYSTEM_NO_DEPRECATED) #define BOOST_SYSTEM_NO_DEPRECATED #endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) // Test that header file is self-contained. #include #include #include #include #include #include "../unit_test.hpp" using boost::asio::awaitable; using namespace boost::asio::experimental::awaitable_operators; struct move_only { move_only(int i) : value(i) {} move_only(const move_only&) = delete; move_only(move_only&&) {} move_only& operator=(const move_only&) = delete; move_only& operator=(move_only&&) { return *this; } int value; }; awaitable void_ok() { co_return; } awaitable void_ex() { throw std::runtime_error("exception"); co_return; } awaitable void_post_loop() { for (;;) co_await boost::asio::post(boost::asio::use_awaitable); } awaitable int_0() { co_return 0; } awaitable int_1() { co_return 1; } awaitable int_2() { co_return 2; } awaitable int_ex() { throw std::runtime_error("exception"); co_return -1; } awaitable move_only_0() { co_return move_only(0); } awaitable move_only_1() { co_return move_only(1); } awaitable move_only_2() { co_return move_only(2); } awaitable move_only_ex() { throw std::runtime_error("exception"); co_return move_only(-1); } awaitable do_test_and_awaitable_operator() { int i; std::tuple ii; std::tuple iii; co_await (void_ok() && void_ok()); co_await (void_ok() && void_ok() && void_ok()); try { co_await (void_ex() && void_ok()); } catch (...) {} try { co_await (void_ex() && void_ok() && void_ok()); } catch (...) {} try { co_await (void_ex() && void_post_loop()); } catch (...) {} try { co_await (void_ex() && void_ok() && void_post_loop()); } catch (...) {} i = co_await (void_ok() && int_0()); BOOST_ASIO_CHECK(i == 0); i = co_await (void_ok() && int_1()); BOOST_ASIO_CHECK(i == 1); i = co_await (int_0() && void_ok()); BOOST_ASIO_CHECK(i == 0); ii = co_await (int_0() && int_1()); BOOST_ASIO_CHECK(std::get<0>(ii) == 0); BOOST_ASIO_CHECK(std::get<1>(ii) == 1); i = co_await (void_ok() && void_ok() && int_0()); BOOST_ASIO_CHECK(i == 0); i = co_await (void_ok() && int_0() && void_ok()); BOOST_ASIO_CHECK(i == 0); ii = co_await (void_ok() && int_0() && int_1()); BOOST_ASIO_CHECK(std::get<0>(ii) == 0); BOOST_ASIO_CHECK(std::get<1>(ii) == 1); ii = co_await (int_0() && void_ok() && int_1()); BOOST_ASIO_CHECK(std::get<0>(ii) == 0); BOOST_ASIO_CHECK(std::get<1>(ii) == 1); iii = co_await (int_0() && int_1() && int_2()); BOOST_ASIO_CHECK(std::get<0>(iii) == 0); BOOST_ASIO_CHECK(std::get<1>(iii) == 1); BOOST_ASIO_CHECK(std::get<2>(iii) == 2); } void test_and_awaitable_operator() { boost::asio::io_context ctx; co_spawn(ctx, do_test_and_awaitable_operator(), boost::asio::detached); ctx.run(); } awaitable do_test_or_awaitable_operator() { std::variant ii; std::variant iv; std::variant vi; std::variant vv; std::variant iii; std::variant iiv; std::variant ivi; std::variant ivv; std::variant vii; std::variant viv; std::variant vvi; std::variant vvv; vv = co_await (void_ok() || void_ok()); BOOST_ASIO_CHECK(vv.index() == 0); vv = co_await (void_ex() || void_ok()); BOOST_ASIO_CHECK(vv.index() == 1); vi = co_await (void_ok() || int_0()); BOOST_ASIO_CHECK(vi.index() == 0); vi = co_await (void_ex() || int_0()); BOOST_ASIO_CHECK(vi.index() == 1); iv = co_await (int_0() || void_ex()); BOOST_ASIO_CHECK(iv.index() == 0); BOOST_ASIO_CHECK(std::get<0>(iv) == 0); ii = co_await (int_0() || int_1()); BOOST_ASIO_CHECK(ii.index() == 0); BOOST_ASIO_CHECK(std::get<0>(ii) == 0); ii = co_await (int_ex() || int_1()); BOOST_ASIO_CHECK(ii.index() == 1); BOOST_ASIO_CHECK(std::get<1>(ii) == 1); vvv = co_await (void_ok() || void_ok() || void_ok()); BOOST_ASIO_CHECK(vvv.index() == 0); vvv = co_await (void_ex() || void_ok() || void_ok()); BOOST_ASIO_CHECK(vvv.index() == 1); vvv = co_await (void_ex() || void_ex() || void_ok()); BOOST_ASIO_CHECK(vvv.index() == 2); vvi = co_await (void_ok() || void_ok() || int_0()); BOOST_ASIO_CHECK(vvi.index() == 0); viv = co_await (void_ok() || int_0() || void_ok()); BOOST_ASIO_CHECK(viv.index() == 0); viv = co_await (void_ex() || int_0() || void_ok()); BOOST_ASIO_CHECK(viv.index() == 1); BOOST_ASIO_CHECK(std::get<1>(viv) == 0); vii = co_await (void_ex() || int_0() || int_1()); BOOST_ASIO_CHECK(vii.index() == 1); BOOST_ASIO_CHECK(std::get<1>(vii) == 0); ivv = co_await (int_0() || void_ok() || void_ok()); BOOST_ASIO_CHECK(ivv.index() == 0); BOOST_ASIO_CHECK(std::get<0>(ivv) == 0); ivv = co_await (int_ex() || void_ok() || void_ok()); BOOST_ASIO_CHECK(ivv.index() == 1); ivi = co_await (int_0() || void_ok() || int_1()); BOOST_ASIO_CHECK(ivi.index() == 0); BOOST_ASIO_CHECK(std::get<0>(ivi) == 0); ivi = co_await (int_ex() || void_ok() || int_1()); BOOST_ASIO_CHECK(ivi.index() == 1); iiv = co_await (int_0() || int_1() || void_ok()); BOOST_ASIO_CHECK(iiv.index() == 0); BOOST_ASIO_CHECK(std::get<0>(iiv) == 0); iiv = co_await (int_ex() || int_1() || void_ok()); BOOST_ASIO_CHECK(iiv.index() == 1); BOOST_ASIO_CHECK(std::get<0>(iiv) == 1); iiv = co_await (int_ex() || int_ex() || void_ok()); BOOST_ASIO_CHECK(iiv.index() == 2); iii = co_await (int_0() || int_1() || int_2()); BOOST_ASIO_CHECK(iii.index() == 0); BOOST_ASIO_CHECK(std::get<0>(iii) == 0); iii = co_await (int_ex() || int_1() || int_2()); BOOST_ASIO_CHECK(iii.index() == 1); BOOST_ASIO_CHECK(std::get<1>(iii) == 1); iii = co_await (int_ex() || int_ex() || int_2()); BOOST_ASIO_CHECK(iii.index() == 2); BOOST_ASIO_CHECK(std::get<2>(iii) == 2); std::variant mi = co_await (move_only_0() || int_1()); BOOST_ASIO_CHECK(mi.index() == 0); BOOST_ASIO_CHECK(std::get<0>(mi).value == 0); mi = co_await (move_only_ex() || int_1()); BOOST_ASIO_CHECK(mi.index() == 1); BOOST_ASIO_CHECK(std::get<1>(mi) == 1); std::variant mm = co_await (move_only_0() || move_only_1()); BOOST_ASIO_CHECK(mm.index() == 0); BOOST_ASIO_CHECK(std::get<0>(mm).value == 0); mm = co_await (move_only_ex() || move_only_1()); BOOST_ASIO_CHECK(mm.index() == 1); BOOST_ASIO_CHECK(std::get<1>(mm).value == 1); std::variant mmm = co_await (move_only_0() || move_only_1() || move_only_2()); BOOST_ASIO_CHECK(mmm.index() == 0); BOOST_ASIO_CHECK(std::get<0>(mmm).value == 0); mmm = co_await (move_only_ex() || move_only_1() || move_only_2()); BOOST_ASIO_CHECK(mmm.index() == 1); BOOST_ASIO_CHECK(std::get<1>(mmm).value == 1); mmm = co_await (move_only_ex() || move_only_ex() || move_only_2()); BOOST_ASIO_CHECK(mmm.index() == 2); BOOST_ASIO_CHECK(std::get<2>(mmm).value == 2); } void test_or_awaitable_operator() { boost::asio::io_context ctx; co_spawn(ctx, do_test_or_awaitable_operator(), boost::asio::detached); ctx.run(); } BOOST_ASIO_TEST_SUITE ( "experimental/awaitable_operators", BOOST_ASIO_TEST_CASE(test_and_awaitable_operator) BOOST_ASIO_TEST_CASE(test_or_awaitable_operator) )