2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-01-24 05:52:17 +00:00
Files
leaf/test/continuation_test.cpp
2019-02-09 18:53:30 -08:00

317 lines
6.9 KiB
C++

// 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 <boost/leaf/preload.hpp>
#include <boost/leaf/handle_error.hpp>
#include <boost/leaf/result.hpp>
#include <deque>
#include <functional>
#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<std::function<void()>> execution_queue;
};
template <typename F>
void post( io_context &io_context, F&& f)
{
io_context.execution_queue.emplace_back(std::forward<F>(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 <fail_where>
struct loc
{
int value;
};
template <int>
struct info
{
int value;
};
leaf::result<int> f( fail_where fw )
{
if( fw == fail_where::f )
return leaf::new_error( loc<fail_where::f>{} );
return 21;
}
leaf::result<int> g( fail_where fw )
{
auto load = leaf::preload( info<1>{} );
if( fw == fail_where::g )
return leaf::new_error( loc<fail_where::g>{} );
return f(fw);
}
struct op_a
{
template <class H>
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<fail_where::op_a_start>{}) );
asio::post( ioc,
[=]() mutable
{
auto load = leaf::preload( info<3>{} );
h(g(fw));
} );
}
};
struct op_b
{
template <class H>
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<fail_where::op_b_start_before_op_a_start>{}) );
op_a::start( ioc, fw,
[=, &ioc]( leaf::result<int> && a1 ) mutable
{
if( !a1 )
return h(std::forward<leaf::result<int>>(a1));
auto load = leaf::preload( info<5>{} );
if( fw == fail_where::op_b_start_after_successful_op_a )
return h( leaf::new_error(loc<fail_where::op_b_start_after_successful_op_a>{}) );
cont(ioc, fw, *a1, h);
} );
}
template <class H>
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<fail_where::op_b_cont_before_op_a_start>{}) );
op_a::start( ioc, fw,
[=]( leaf::result<int> && a2 ) mutable
{
if( !a2 )
return h(std::forward<leaf::result<int>>(a2));
auto load = leaf::preload( info<7>{} );
if( fw == fail_where::op_b_cont_after_successful_op_a )
return h( leaf::new_error(loc<fail_where::op_b_cont_after_successful_op_a>{}) );
h(a1 + *a2);
} );
}
};
///////////////////////////////
int main()
{
auto try_block =
[ ]( fail_where fw )
{
asio::io_context ioc;
leaf::result<int> res;
op_b::start( ioc, fw,
[&]( leaf::result<int> && 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<fail_where::f>, 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<fail_where::op_a_start>, 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<fail_where::op_b_start_before_op_a_start>, 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<fail_where::op_b_start_after_successful_op_a>, 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<fail_where::op_b_cont_before_op_a_start>, 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<fail_where::op_b_cont_after_successful_op_a>, 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();
}