// Copyright (c) 2018-2019 Emil Dotchevski // Copyright (c) 2018-2019 Second Spectrum, Inc. // 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) #include #include #include #include #include #include "boost/core/lightweight_test.hpp" namespace asio_simulator { struct io_context { io_context( io_context const & ) = delete; io_context & operator=( io_context const & ) = delete; io_context() noexcept { } void run() noexcept { while (!execution_queue.empty()) { auto e = std::move(execution_queue.front()); execution_queue.pop_front(); e(); } } std::deque> execution_queue; }; template void post( io_context &io_context, F&& f) { io_context.execution_queue.emplace_back(std::forward(f)); } } namespace asio = asio_simulator; namespace leaf = boost::leaf; enum class fail_where { nowhere, f, g, op_a_start, op_b_start_before_op_a_start, op_b_start_after_successful_op_a, op_b_cont_before_op_a_start, op_b_cont_after_successful_op_a }; template struct loc { int value; }; template struct info { int value; }; leaf::result f( fail_where fw ) { if( fw == fail_where::f ) return leaf::new_error( loc{} ); return 21; } leaf::result g( fail_where fw ) { auto load = leaf::preload( info<1>{} ); if( fw == fail_where::g ) return leaf::new_error( loc{} ); return f(fw); } struct op_a { template static void start( asio::io_context & ioc, fail_where fw, H h ) { auto load = leaf::preload( info<2>{} ); if( fw == fail_where::op_a_start ) return h( leaf::new_error(loc{}) ); asio::post( ioc, [=]() mutable { auto load = leaf::preload( info<3>{} ); h(g(fw)); } ); } }; struct op_b { template static void start( asio::io_context & ioc, fail_where fw, H h ) { auto load = leaf::preload( info<4>{} ); if( fw == fail_where::op_b_start_before_op_a_start ) return h( leaf::new_error(loc{}) ); op_a::start( ioc, fw, [=, &ioc]( leaf::result && a1 ) mutable { if( !a1 ) return h(std::forward>(a1)); auto load = leaf::preload( info<5>{} ); if( fw == fail_where::op_b_start_after_successful_op_a ) return h( leaf::new_error(loc{}) ); cont(ioc, fw, *a1, h); } ); } template static void cont( asio::io_context & ioc, fail_where fw, int a1, H h ) { auto load = leaf::preload( info<6>{} ); if( fw == fail_where::op_b_cont_before_op_a_start ) return h( leaf::new_error(loc{}) ); op_a::start( ioc, fw, [=]( leaf::result && a2 ) mutable { if( !a2 ) return h(std::forward>(a2)); auto load = leaf::preload( info<7>{} ); if( fw == fail_where::op_b_cont_after_successful_op_a ) return h( leaf::new_error(loc{}) ); h(a1 + *a2); } ); } }; /////////////////////////////// int main() { auto try_block = [ ]( fail_where fw ) { asio::io_context ioc; leaf::result res; op_b::start( ioc, fw, [&]( leaf::result && answer ) mutable { res = make_continuation_result(std::move(answer)); } ); if( res ) ioc.run(); return res; }; { int r = leaf::try_handle_all( [&] { return try_block(fail_where::f); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 != 0); BOOST_TEST(i2 == 0); BOOST_TEST(i3 != 0); BOOST_TEST(i4 == 0); BOOST_TEST(i5 == 0); BOOST_TEST(i6 == 0); BOOST_TEST(i7 == 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } { int r = leaf::try_handle_all( [&] { return try_block(fail_where::op_a_start); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 == 0); BOOST_TEST(i2 != 0); BOOST_TEST(i3 == 0); BOOST_TEST(i4 != 0); BOOST_TEST(i5 == 0); BOOST_TEST(i6 == 0); BOOST_TEST(i7 == 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } { int r = leaf::try_handle_all( [&] { return try_block(fail_where::op_b_start_before_op_a_start); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 == 0); BOOST_TEST(i2 == 0); BOOST_TEST(i3 == 0); BOOST_TEST(i4 != 0); BOOST_TEST(i5 == 0); BOOST_TEST(i6 == 0); BOOST_TEST(i7 == 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } { int r = leaf::try_handle_all( [&] { return try_block(fail_where::op_b_start_after_successful_op_a); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 == 0); BOOST_TEST(i2 == 0); BOOST_TEST(i3 != 0); BOOST_TEST(i4 == 0); BOOST_TEST(i5 != 0); BOOST_TEST(i6 == 0); BOOST_TEST(i7 == 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } { int r = leaf::try_handle_all( [&] { return try_block(fail_where::op_b_cont_before_op_a_start); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 == 0); BOOST_TEST(i2 == 0); BOOST_TEST(i3 != 0); BOOST_TEST(i4 == 0); BOOST_TEST(i5 != 0); BOOST_TEST(i6 != 0); BOOST_TEST(i7 == 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } { int r = leaf::try_handle_all( [&] { return try_block(fail_where::op_b_cont_after_successful_op_a); }, [ ]( loc, info<1> const * i1, info<2> const * i2, info<3> const * i3, info<4> const * i4, info<5> const * i5, info<6> const * i6, info<7> const * i7 ) { BOOST_TEST(i1 == 0); BOOST_TEST(i2 == 0); BOOST_TEST(i3 != 0); BOOST_TEST(i4 == 0); BOOST_TEST(i5 == 0); BOOST_TEST(i6 == 0); BOOST_TEST(i7 != 0); return 1; }, [ ] { return 2; } ); BOOST_TEST_EQ(r, 1); } return boost::report_errors(); }