2019-01-05 18:51:47 -08:00
|
|
|
//
|
2019-02-21 07:00:31 -08:00
|
|
|
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2019-01-05 18:51:47 -08:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
// Official repository: https://github.com/boostorg/beast
|
|
|
|
//
|
|
|
|
|
|
|
|
// Test that header file is self-contained.
|
2019-02-25 09:31:51 -08:00
|
|
|
#include <boost/beast/core/async_base.hpp>
|
2019-01-05 18:51:47 -08:00
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
#include "test_handler.hpp"
|
|
|
|
|
2019-01-05 18:51:47 -08:00
|
|
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
2019-02-15 15:16:51 -08:00
|
|
|
#include <boost/beast/_experimental/test/handler.hpp>
|
2019-01-07 13:35:19 -08:00
|
|
|
#include <boost/beast/_experimental/test/stream.hpp>
|
2019-01-05 18:51:47 -08:00
|
|
|
#include <boost/beast/core/error.hpp>
|
2019-01-07 13:35:19 -08:00
|
|
|
#include <boost/asio/async_result.hpp>
|
2019-03-06 10:36:48 -08:00
|
|
|
#include <boost/asio/coroutine.hpp>
|
2019-01-05 18:51:47 -08:00
|
|
|
#include <boost/asio/io_context.hpp>
|
2019-01-07 13:35:19 -08:00
|
|
|
#include <boost/asio/steady_timer.hpp>
|
2019-01-05 18:51:47 -08:00
|
|
|
#include <boost/asio/system_executor.hpp>
|
2019-01-07 13:35:19 -08:00
|
|
|
#include <boost/asio/write.hpp>
|
2019-01-05 18:51:47 -08:00
|
|
|
#include <boost/core/ignore_unused.hpp>
|
2019-01-09 16:11:15 -08:00
|
|
|
#include <stdexcept>
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace boost {
|
|
|
|
namespace beast {
|
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
namespace {
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
struct ex1_type
|
|
|
|
{
|
|
|
|
void* context() { return nullptr; }
|
|
|
|
void on_work_started() {}
|
|
|
|
void on_work_finished() {}
|
|
|
|
template<class F> void dispatch(F&&) {}
|
|
|
|
template<class F> void post(F&&) {}
|
|
|
|
template<class F> void defer(F&&) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct no_alloc
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nested_alloc
|
|
|
|
{
|
|
|
|
struct allocator_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct intrusive_alloc
|
|
|
|
{
|
|
|
|
struct allocator_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct no_ex
|
|
|
|
{
|
|
|
|
using executor_type = net::system_executor;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nested_ex
|
|
|
|
{
|
|
|
|
struct executor_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct intrusive_ex
|
|
|
|
{
|
|
|
|
struct executor_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class E, class A>
|
|
|
|
struct handler;
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct handler<no_ex, no_alloc>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct handler<no_ex, nested_alloc>
|
|
|
|
: nested_alloc
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct handler<no_ex, intrusive_alloc>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct handler<nested_ex, no_alloc>
|
|
|
|
: nested_ex
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct handler<intrusive_ex, no_alloc>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
} // (anon)
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
} // beast
|
|
|
|
} // boost
|
|
|
|
|
|
|
|
namespace boost {
|
|
|
|
namespace asio {
|
|
|
|
|
|
|
|
template<class Allocator>
|
|
|
|
struct associated_allocator<
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::handler<
|
|
|
|
boost::beast::no_ex,
|
|
|
|
boost::beast::intrusive_alloc>,
|
2019-01-05 18:51:47 -08:00
|
|
|
Allocator>
|
|
|
|
{
|
|
|
|
using type =
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::intrusive_alloc::allocator_type;
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
static type get(
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::handler<
|
|
|
|
boost::beast::no_ex,
|
|
|
|
boost::beast::intrusive_alloc> const& h,
|
2019-01-05 18:51:47 -08:00
|
|
|
Allocator const& a = Allocator()) noexcept
|
|
|
|
{
|
|
|
|
return type{};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Executor>
|
|
|
|
struct associated_executor<
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::handler<
|
|
|
|
boost::beast::intrusive_ex,
|
|
|
|
boost::beast::no_alloc>,
|
2019-01-05 18:51:47 -08:00
|
|
|
Executor>
|
|
|
|
{
|
|
|
|
using type =
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::intrusive_ex::executor_type;
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
static type get(
|
2019-01-07 13:35:19 -08:00
|
|
|
boost::beast::handler<
|
|
|
|
boost::beast::intrusive_ex,
|
|
|
|
boost::beast::no_alloc> const& h,
|
2019-01-05 18:51:47 -08:00
|
|
|
Executor const& a = Executor()) noexcept
|
|
|
|
{
|
|
|
|
return type{};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // asio
|
|
|
|
} // boost
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace boost {
|
|
|
|
namespace beast {
|
|
|
|
|
2019-02-25 09:31:51 -08:00
|
|
|
class async_base_test : public beast::unit_test::suite
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
// no associated allocator
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
std::allocator<void>,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
net::io_context::executor_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
std::allocator<int>,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
std::allocator<void>,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
net::io_context::executor_type>,
|
|
|
|
std::allocator<int> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
std::allocator<int>,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>>,
|
|
|
|
std::allocator<double> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
// nested associated allocator
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, nested_alloc>,
|
|
|
|
net::io_context::executor_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, nested_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, nested_alloc>,
|
|
|
|
net::io_context::executor_type>,
|
|
|
|
std::allocator<int> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, nested_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>>, // ignored
|
|
|
|
std::allocator<int> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
// intrusive associated allocator
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, intrusive_alloc>,
|
|
|
|
net::io_context::executor_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, intrusive_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, intrusive_alloc>,
|
|
|
|
net::io_context::executor_type>,
|
|
|
|
std::allocator<int> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_alloc::allocator_type,
|
|
|
|
net::associated_allocator_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, intrusive_alloc>,
|
|
|
|
net::io_context::executor_type,
|
|
|
|
std::allocator<int>>, // ignored
|
|
|
|
std::allocator<int> // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
// no associated executor
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
ex1_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
ex1_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
ex1_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<no_ex, no_alloc>,
|
|
|
|
ex1_type>,
|
|
|
|
net::system_executor // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
// nested associated executor
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_ex::executor_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<nested_ex, no_alloc>,
|
|
|
|
ex1_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
nested_ex::executor_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<nested_ex, no_alloc>,
|
|
|
|
ex1_type>,
|
|
|
|
net::system_executor // ignored
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
// intrusive associated executor
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_ex::executor_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<intrusive_ex, no_alloc>,
|
|
|
|
ex1_type>
|
|
|
|
>>::value);
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
std::is_same<
|
|
|
|
intrusive_ex::executor_type,
|
|
|
|
net::associated_executor_t<
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-05 18:51:47 -08:00
|
|
|
handler<intrusive_ex, no_alloc>,
|
|
|
|
ex1_type>,
|
|
|
|
net::system_executor // ignored
|
|
|
|
>>::value);
|
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
struct final_handler
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
bool& invoked;
|
2019-01-05 18:51:47 -08:00
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
void
|
|
|
|
operator()()
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
invoked = true;
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2019-01-09 16:11:15 -08:00
|
|
|
testBase()
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
// get_allocator
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
simple_allocator alloc;
|
|
|
|
simple_allocator alloc2;
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor,
|
|
|
|
simple_allocator> op(
|
|
|
|
move_only_handler{}, {}, alloc);
|
|
|
|
BEAST_EXPECT(op.get_allocator() == alloc);
|
|
|
|
BEAST_EXPECT(op.get_allocator() != alloc2);
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
// get_executor
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
simple_executor ex;
|
|
|
|
simple_executor ex2;
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, ex);
|
|
|
|
BEAST_EXPECT(op.get_executor() == ex);
|
|
|
|
BEAST_EXPECT(op.get_executor() != ex2);
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
// move construction
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, {});
|
|
|
|
auto op2 = std::move(op);
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:11:15 -08:00
|
|
|
// observers
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
bool b = false;
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
legacy_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
legacy_handler{b}, {});
|
|
|
|
BEAST_EXPECT(! op.handler().hook_invoked);
|
|
|
|
b = true;
|
|
|
|
BEAST_EXPECT(op.handler().hook_invoked);
|
|
|
|
b = false;
|
|
|
|
BEAST_EXPECT(! op.release_handler().hook_invoked);
|
|
|
|
}
|
|
|
|
|
|
|
|
// invocation
|
|
|
|
{
|
2019-02-15 15:16:51 -08:00
|
|
|
net::io_context ioc;
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
|
|
|
net::io_context::executor_type> op(
|
|
|
|
test::any_handler(), ioc.get_executor());
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete(true);
|
2019-02-15 15:16:51 -08:00
|
|
|
}
|
|
|
|
{
|
|
|
|
net::io_context ioc;
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
|
|
|
net::io_context::executor_type> op(
|
|
|
|
test::any_handler(), ioc.get_executor());
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete(false);
|
2019-02-15 15:16:51 -08:00
|
|
|
ioc.run();
|
|
|
|
}
|
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
2019-01-09 16:11:15 -08:00
|
|
|
simple_executor> op(
|
2019-02-15 15:16:51 -08:00
|
|
|
test::any_handler(), {});
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete_now();
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
2019-01-09 16:11:15 -08:00
|
|
|
|
|
|
|
// legacy hooks
|
2019-01-16 06:39:10 -08:00
|
|
|
legacy_handler::test(
|
2019-01-09 16:11:15 -08:00
|
|
|
[](legacy_handler h)
|
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
return async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
legacy_handler,
|
|
|
|
simple_executor>(
|
|
|
|
std::move(h), {});
|
|
|
|
});
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-01-09 16:11:15 -08:00
|
|
|
testStableBase()
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
// get_allocator
|
|
|
|
{
|
|
|
|
simple_allocator alloc;
|
|
|
|
simple_allocator alloc2;
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor,
|
|
|
|
simple_allocator> op(
|
|
|
|
move_only_handler{}, {}, alloc);
|
|
|
|
BEAST_EXPECT(op.get_allocator() == alloc);
|
|
|
|
BEAST_EXPECT(op.get_allocator() != alloc2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get_executor
|
|
|
|
{
|
|
|
|
simple_executor ex;
|
|
|
|
simple_executor ex2;
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, ex);
|
|
|
|
BEAST_EXPECT(op.get_executor() == ex);
|
|
|
|
BEAST_EXPECT(op.get_executor() != ex2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// move construction
|
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, {});
|
|
|
|
auto op2 = std::move(op);
|
|
|
|
}
|
|
|
|
|
|
|
|
// invocation
|
|
|
|
{
|
2019-02-15 15:16:51 -08:00
|
|
|
net::io_context ioc;
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
|
|
|
net::io_context::executor_type> op(
|
|
|
|
test::any_handler(), ioc.get_executor());
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete(true);
|
2019-02-15 15:16:51 -08:00
|
|
|
}
|
|
|
|
{
|
|
|
|
net::io_context ioc;
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
|
|
|
net::io_context::executor_type> op(
|
|
|
|
test::any_handler(), ioc.get_executor());
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete(false);
|
2019-02-15 15:16:51 -08:00
|
|
|
ioc.run();
|
|
|
|
}
|
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-02-15 15:16:51 -08:00
|
|
|
test::handler,
|
2019-01-09 16:11:15 -08:00
|
|
|
simple_executor> op(
|
2019-02-15 15:16:51 -08:00
|
|
|
test::any_handler(), {});
|
2019-03-06 08:09:35 -08:00
|
|
|
op.complete_now();
|
2019-01-09 16:11:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// legacy hooks
|
2019-01-16 06:39:10 -08:00
|
|
|
legacy_handler::test(
|
2019-01-09 16:11:15 -08:00
|
|
|
[](legacy_handler h)
|
|
|
|
{
|
2019-02-25 09:31:51 -08:00
|
|
|
return stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
legacy_handler,
|
|
|
|
simple_executor>(
|
|
|
|
std::move(h), {});
|
|
|
|
});
|
|
|
|
|
|
|
|
// allocate_stable
|
|
|
|
|
|
|
|
{
|
|
|
|
bool destroyed = false;
|
|
|
|
{
|
|
|
|
struct data
|
|
|
|
{
|
|
|
|
bool& destroyed;
|
|
|
|
|
|
|
|
~data()
|
|
|
|
{
|
|
|
|
destroyed = true;
|
|
|
|
}
|
|
|
|
};
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, {});
|
|
|
|
BEAST_EXPECT(! destroyed);
|
|
|
|
auto& d = allocate_stable<data>(op, destroyed);
|
|
|
|
BEAST_EXPECT(! d.destroyed);
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(destroyed);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
struct throwing_data
|
|
|
|
{
|
|
|
|
throwing_data()
|
|
|
|
{
|
|
|
|
BOOST_THROW_EXCEPTION(
|
|
|
|
std::exception{});
|
|
|
|
}
|
|
|
|
};
|
2019-02-25 09:31:51 -08:00
|
|
|
stable_async_base<
|
2019-01-09 16:11:15 -08:00
|
|
|
move_only_handler,
|
|
|
|
simple_executor> op(
|
|
|
|
move_only_handler{}, {});
|
|
|
|
try
|
|
|
|
{
|
|
|
|
allocate_stable<throwing_data>(op);
|
|
|
|
fail();
|
|
|
|
}
|
|
|
|
catch(std::exception const&)
|
|
|
|
{
|
|
|
|
pass();
|
|
|
|
}
|
|
|
|
}
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
// Asynchronously read into a buffer until the buffer is full, or an error occurs
|
|
|
|
template<class AsyncReadStream, class ReadHandler>
|
2019-03-04 23:13:42 -08:00
|
|
|
typename net::async_result<ReadHandler, void(error_code, std::size_t)>::return_type
|
2019-01-07 13:35:19 -08:00
|
|
|
async_read(AsyncReadStream& stream, net::mutable_buffer buffer, ReadHandler&& handler)
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-07 13:35:19 -08:00
|
|
|
using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t));
|
2019-02-25 09:31:51 -08:00
|
|
|
using base_type = async_base<handler_type, typename AsyncReadStream::executor_type>;
|
2019-01-05 18:51:47 -08:00
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
struct op : base_type
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
|
|
|
AsyncReadStream& stream_;
|
2019-01-07 13:35:19 -08:00
|
|
|
net::mutable_buffer buffer_;
|
|
|
|
std::size_t total_bytes_transferred_;
|
|
|
|
|
|
|
|
op(
|
|
|
|
AsyncReadStream& stream,
|
|
|
|
net::mutable_buffer buffer,
|
|
|
|
handler_type& handler)
|
2019-01-09 16:11:15 -08:00
|
|
|
: base_type(std::move(handler), stream.get_executor())
|
2019-01-07 13:35:19 -08:00
|
|
|
, stream_(stream)
|
|
|
|
, buffer_(buffer)
|
|
|
|
, total_bytes_transferred_(0)
|
|
|
|
{
|
|
|
|
(*this)({}, 0, false); // start the operation
|
|
|
|
}
|
2019-01-05 18:51:47 -08:00
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
void operator()(error_code ec, std::size_t bytes_transferred, bool is_continuation = true)
|
2019-01-05 18:51:47 -08:00
|
|
|
{
|
2019-01-07 13:35:19 -08:00
|
|
|
// Adjust the count of bytes and advance our buffer
|
|
|
|
total_bytes_transferred_ += bytes_transferred;
|
|
|
|
buffer_ = buffer_ + bytes_transferred;
|
|
|
|
|
|
|
|
// Keep reading until buffer is full or an error occurs
|
|
|
|
if(! ec && buffer_.size() > 0)
|
|
|
|
return stream_.async_read_some(buffer_, std::move(*this));
|
2019-01-05 18:51:47 -08:00
|
|
|
|
2019-02-15 15:47:36 -08:00
|
|
|
// Call the completion handler with the result. If `is_continuation` is
|
|
|
|
// false, which happens on the first time through this function, then
|
|
|
|
// `net::post` will be used to call the completion handler, otherwise
|
|
|
|
// the completion handler will be invoked directly.
|
2019-01-07 13:35:19 -08:00
|
|
|
|
2019-03-06 08:09:35 -08:00
|
|
|
this->complete(is_continuation, ec, total_bytes_transferred_);
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
net::async_completion<ReadHandler, void(error_code, std::size_t)> init{handler};
|
|
|
|
op(stream, buffer, init.completion_handler);
|
2019-01-05 18:51:47 -08:00
|
|
|
return init.result.get();
|
|
|
|
}
|
2019-01-07 13:35:19 -08:00
|
|
|
|
|
|
|
// Asynchronously send a message multiple times, once per second
|
|
|
|
template <class AsyncWriteStream, class T, class WriteHandler>
|
|
|
|
auto async_write_messages(
|
|
|
|
AsyncWriteStream& stream,
|
|
|
|
T const& message,
|
|
|
|
std::size_t repeat_count,
|
|
|
|
WriteHandler&& handler) ->
|
|
|
|
typename net::async_result<
|
|
|
|
typename std::decay<WriteHandler>::type,
|
|
|
|
void(error_code)>::return_type
|
|
|
|
{
|
|
|
|
using handler_type = typename net::async_completion<WriteHandler, void(error_code)>::completion_handler_type;
|
2019-02-25 09:31:51 -08:00
|
|
|
using base_type = stable_async_base<handler_type, typename AsyncWriteStream::executor_type>;
|
2019-01-07 13:35:19 -08:00
|
|
|
|
2019-03-06 10:36:48 -08:00
|
|
|
struct op : base_type, boost::asio::coroutine
|
2019-01-07 13:35:19 -08:00
|
|
|
{
|
|
|
|
// This object must have a stable address
|
|
|
|
struct temporary_data
|
|
|
|
{
|
2019-03-06 10:36:48 -08:00
|
|
|
// Although std::string is in theory movable, most implementations
|
|
|
|
// use a "small buffer optimization" which means that we might
|
|
|
|
// be submitting a buffer to the write operation and then
|
|
|
|
// moving the string, invalidating the buffer. To prevent
|
|
|
|
// undefined behavior we store the string object itself at
|
|
|
|
// a stable location.
|
2019-01-07 13:35:19 -08:00
|
|
|
std::string const message;
|
2019-03-06 10:36:48 -08:00
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
net::steady_timer timer;
|
|
|
|
|
|
|
|
temporary_data(std::string message_, net::io_context& ctx)
|
|
|
|
: message(std::move(message_))
|
|
|
|
, timer(ctx)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AsyncWriteStream& stream_;
|
|
|
|
std::size_t repeats_;
|
|
|
|
temporary_data& data_;
|
|
|
|
|
|
|
|
op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler)
|
2019-01-09 16:11:15 -08:00
|
|
|
: base_type(std::move(handler), stream.get_executor())
|
2019-01-07 13:35:19 -08:00
|
|
|
, stream_(stream)
|
|
|
|
, repeats_(repeats)
|
|
|
|
, data_(allocate_stable<temporary_data>(*this, std::move(message), stream.get_executor().context()))
|
|
|
|
{
|
|
|
|
(*this)(); // start the operation
|
|
|
|
}
|
|
|
|
|
2019-03-06 10:36:48 -08:00
|
|
|
// Including this file provides the keywords for macro-based coroutines
|
|
|
|
#include <boost/asio/yield.hpp>
|
|
|
|
|
2019-01-07 13:35:19 -08:00
|
|
|
void operator()(error_code ec = {}, std::size_t = 0)
|
|
|
|
{
|
2019-03-06 10:36:48 -08:00
|
|
|
reenter(*this)
|
2019-01-07 13:35:19 -08:00
|
|
|
{
|
2019-03-06 10:36:48 -08:00
|
|
|
// If repeats starts at 0 then we must complete immediately. But
|
|
|
|
// we can't call the final handler from inside the initiating
|
|
|
|
// function, so we post our intermediate handler first. We use
|
|
|
|
// net::async_write with an empty buffer instead of calling
|
|
|
|
// net::post to avoid an extra function template instantiation, to
|
|
|
|
// keep compile times lower and make the resulting executable smaller.
|
|
|
|
yield net::async_write(stream_, net::const_buffer{}, std::move(*this));
|
|
|
|
while(! ec && repeats_-- > 0)
|
2019-01-07 13:35:19 -08:00
|
|
|
{
|
2019-03-06 10:36:48 -08:00
|
|
|
// Send the string. We construct a `const_buffer` here to guarantee
|
|
|
|
// that we do not create an additional function template instantation
|
|
|
|
// of net::async_write, since we already instantiated it above for
|
|
|
|
// net::const_buffer.
|
|
|
|
|
|
|
|
yield net::async_write(stream_,
|
|
|
|
net::const_buffer(net::buffer(data_.message)), std::move(*this));
|
|
|
|
if(ec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Set the timer and wait
|
|
|
|
data_.timer.expires_after(std::chrono::seconds(1));
|
|
|
|
yield data_.timer.async_wait(std::move(*this));
|
2019-01-07 13:35:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-06 10:36:48 -08:00
|
|
|
// The base class destroys the temporary data automatically,
|
|
|
|
// before invoking the final completion handler
|
2019-03-06 08:09:35 -08:00
|
|
|
this->complete_now(ec);
|
2019-01-07 13:35:19 -08:00
|
|
|
}
|
2019-03-06 10:36:48 -08:00
|
|
|
|
|
|
|
// Including this file undefines the macros for the coroutines
|
|
|
|
#include <boost/asio/unyield.hpp>
|
2019-01-07 13:35:19 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
net::async_completion<WriteHandler, void(error_code)> completion(handler);
|
|
|
|
std::ostringstream os;
|
|
|
|
os << message;
|
|
|
|
op(stream, repeat_count, os.str(), completion.completion_handler);
|
|
|
|
return completion.result.get();
|
|
|
|
}
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
testJavadocs()
|
|
|
|
{
|
2019-01-07 13:35:19 -08:00
|
|
|
struct handler
|
|
|
|
{
|
|
|
|
void operator()(error_code = {}, std::size_t = 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-25 09:31:51 -08:00
|
|
|
BEAST_EXPECT((&async_base_test::async_read<test::stream, handler>));
|
|
|
|
BEAST_EXPECT((&async_base_test::async_write_messages<test::stream, std::string, handler>));
|
2019-01-05 18:51:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void
|
|
|
|
run() override
|
|
|
|
{
|
2019-01-09 16:11:15 -08:00
|
|
|
testBase();
|
|
|
|
testStableBase();
|
2019-01-05 18:51:47 -08:00
|
|
|
testJavadocs();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-25 09:31:51 -08:00
|
|
|
BEAST_DEFINE_TESTSUITE(beast,core,async_base);
|
2019-01-05 18:51:47 -08:00
|
|
|
|
|
|
|
} // beast
|
|
|
|
} // boost
|