// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail 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) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_DETAIL_IMPL_READ_HPP #define BOOST_BEAST_DETAIL_IMPL_READ_HPP #include #include #include #include #include #include namespace boost { namespace beast { namespace detail { // The number of bytes in the stack buffer when using non-blocking. static std::size_t constexpr default_max_stack_buffer = 16384; //------------------------------------------------------------------------------ struct dynamic_read_ops { // read into a dynamic buffer until the // condition is met or an error occurs template< class Stream, class DynamicBuffer, class Condition, class Handler> class read_op : public asio::coroutine , public async_base< Handler, beast::executor_type> { Stream& s_; DynamicBuffer& b_; Condition cond_; error_code ec_; std::size_t total_ = 0; public: read_op(read_op&&) = default; template read_op( Handler_&& h, Stream& s, DynamicBuffer& b, Condition_&& cond) : async_base>( std::forward(h), s.get_executor()) , s_(s) , b_(b) , cond_(std::forward(cond)) { (*this)({}, 0, false); } void operator()( error_code ec, std::size_t bytes_transferred, bool cont = true) { std::size_t max_prepare; BOOST_ASIO_CORO_REENTER(*this) { for(;;) { max_prepare = beast::read_size(b_, cond_(ec, total_, b_)); if(max_prepare == 0) break; BOOST_ASIO_CORO_YIELD s_.async_read_some( b_.prepare(max_prepare), std::move(*this)); b_.commit(bytes_transferred); total_ += bytes_transferred; } if(! cont) { // run this handler "as-if" using net::post // to reduce template instantiations ec_ = ec; BOOST_ASIO_CORO_YIELD s_.async_read_some( b_.prepare(0), std::move(*this)); BOOST_BEAST_ASSIGN_EC(ec, ec_); } this->complete_now(ec, total_); } } }; //------------------------------------------------------------------------------ template struct run_read_op { AsyncReadStream* stream; using executor_type = typename AsyncReadStream::executor_type; executor_type get_executor() const noexcept { return stream->get_executor(); } template< class DynamicBuffer, class Condition, class ReadHandler> void operator()( ReadHandler&& h, DynamicBuffer* b, Condition&& c) { // If you get an error on the following line it means // that your handler does not meet the documented type // requirements for the handler. static_assert( beast::detail::is_invocable::value, "ReadHandler type requirements not met"); read_op< AsyncReadStream, DynamicBuffer, typename std::decay::type, typename std::decay::type>( std::forward(h), *stream, *b, std::forward(c)); } }; }; //------------------------------------------------------------------------------ template< class SyncReadStream, class DynamicBuffer, class CompletionCondition, class> std::size_t read( SyncReadStream& stream, DynamicBuffer& buffer, CompletionCondition cond) { static_assert(is_sync_read_stream::value, "SyncReadStream type requirements not met"); static_assert( net::is_dynamic_buffer::value, "DynamicBuffer type requirements not met"); static_assert( detail::is_invocable::value, "CompletionCondition type requirements not met"); error_code ec; auto const bytes_transferred = detail::read( stream, buffer, std::move(cond), ec); if(ec) BOOST_THROW_EXCEPTION(system_error{ec}); return bytes_transferred; } template< class SyncReadStream, class DynamicBuffer, class CompletionCondition, class> std::size_t read( SyncReadStream& stream, DynamicBuffer& buffer, CompletionCondition cond, error_code& ec) { static_assert(is_sync_read_stream::value, "SyncReadStream type requirements not met"); static_assert( net::is_dynamic_buffer::value, "DynamicBuffer type requirements not met"); static_assert( detail::is_invocable::value, "CompletionCondition type requirements not met"); ec = {}; std::size_t total = 0; std::size_t max_prepare; for(;;) { max_prepare = beast::read_size(buffer, cond(ec, total, buffer)); if(max_prepare == 0) break; std::size_t const bytes_transferred = stream.read_some(buffer.prepare(max_prepare), ec); buffer.commit(bytes_transferred); total += bytes_transferred; } return total; } template< class AsyncReadStream, class DynamicBuffer, class CompletionCondition, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler, class> BOOST_BEAST_ASYNC_RESULT2(ReadHandler) async_read( AsyncReadStream& stream, DynamicBuffer& buffer, CompletionCondition&& cond, ReadHandler&& handler) { static_assert(is_async_read_stream::value, "AsyncReadStream type requirements not met"); static_assert( net::is_dynamic_buffer::value, "DynamicBuffer type requirements not met"); static_assert( detail::is_invocable::value, "CompletionCondition type requirements not met"); return net::async_initiate< ReadHandler, void(error_code, std::size_t)>( typename dynamic_read_ops::run_read_op{&stream}, handler, &buffer, std::forward(cond)); } } // detail } // beast } // boost #endif