// // Copyright (c) 2013-2017 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) // #ifndef BEAST_IMPL_DYNABUF_READSTREAM_HPP #define BEAST_IMPL_DYNABUF_READSTREAM_HPP #include #include #include #include #include namespace beast { template template class dynabuf_readstream< Stream, DynamicBuffer>::read_some_op { // VFALCO What about bool cont for is_continuation? struct data { dynabuf_readstream& srs; MutableBufferSequence bs; int state = 0; data(Handler&, dynabuf_readstream& srs_, MutableBufferSequence const& bs_) : srs(srs_) , bs(bs_) { } }; handler_ptr d_; public: read_some_op(read_some_op&&) = default; read_some_op(read_some_op const&) = default; template read_some_op(DeducedHandler&& h, dynabuf_readstream& srs, Args&&... args) : d_(std::forward(h), srs, std::forward(args)...) { (*this)(error_code{}, 0); } void operator()(error_code const& ec, std::size_t bytes_transferred); friend void* asio_handler_allocate( std::size_t size, read_some_op* op) { return beast_asio_helpers:: allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, read_some_op* op) { return beast_asio_helpers:: deallocate(p, size, op->d_.handler()); } friend bool asio_handler_is_continuation(read_some_op* op) { return beast_asio_helpers:: is_continuation(op->d_.handler()); } template friend void asio_handler_invoke(Function&& f, read_some_op* op) { return beast_asio_helpers:: invoke(f, op->d_.handler()); } }; template template void dynabuf_readstream:: read_some_op::operator()( error_code const& ec, std::size_t bytes_transferred) { auto& d = *d_; while(! ec && d.state != 99) { switch(d.state) { case 0: if(d.srs.sb_.size() == 0) { d.state = d.srs.capacity_ > 0 ? 2 : 1; break; } d.state = 4; d.srs.get_io_service().post( bind_handler(std::move(*this), ec, 0)); return; case 1: // read (unbuffered) d.state = 99; d.srs.next_layer_.async_read_some( d.bs, std::move(*this)); return; case 2: // read d.state = 3; d.srs.next_layer_.async_read_some( d.srs.sb_.prepare(d.srs.capacity_), std::move(*this)); return; // got data case 3: d.state = 4; d.srs.sb_.commit(bytes_transferred); break; // copy case 4: bytes_transferred = boost::asio::buffer_copy( d.bs, d.srs.sb_.data()); d.srs.sb_.consume(bytes_transferred); // call handler d.state = 99; break; } } d_.invoke(ec, bytes_transferred); } //------------------------------------------------------------------------------ template template dynabuf_readstream:: dynabuf_readstream(Args&&... args) : next_layer_(std::forward(args)...) { } template template auto dynabuf_readstream:: async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler) -> typename async_completion< WriteHandler, void(error_code)>::result_type { static_assert(is_AsyncWriteStream::value, "AsyncWriteStream requirements not met"); static_assert(is_ConstBufferSequence< ConstBufferSequence>::value, "ConstBufferSequence requirements not met"); static_assert(is_CompletionHandler::value, "WriteHandler requirements not met"); return next_layer_.async_write_some(buffers, std::forward(handler)); } template template std::size_t dynabuf_readstream:: read_some( MutableBufferSequence const& buffers) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_MutableBufferSequence< MutableBufferSequence>::value, "MutableBufferSequence requirements not met"); error_code ec; auto n = read_some(buffers, ec); if(ec) throw system_error{ec}; return n; } template template std::size_t dynabuf_readstream:: read_some(MutableBufferSequence const& buffers, error_code& ec) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_MutableBufferSequence< MutableBufferSequence>::value, "MutableBufferSequence requirements not met"); using boost::asio::buffer_size; using boost::asio::buffer_copy; if(sb_.size() == 0) { if(capacity_ == 0) return next_layer_.read_some(buffers, ec); sb_.commit(next_layer_.read_some( sb_.prepare(capacity_), ec)); if(ec) return 0; } auto bytes_transferred = buffer_copy(buffers, sb_.data()); sb_.consume(bytes_transferred); return bytes_transferred; } template template auto dynabuf_readstream:: async_read_some( MutableBufferSequence const& buffers, ReadHandler&& handler) -> typename async_completion< ReadHandler, void(error_code)>::result_type { static_assert(is_AsyncReadStream::value, "Stream requirements not met"); static_assert(is_MutableBufferSequence< MutableBufferSequence>::value, "MutableBufferSequence requirements not met"); beast::async_completion< ReadHandler, void(error_code, std::size_t) > completion{handler}; read_some_op{ completion.handler, *this, buffers}; return completion.result.get(); } } // beast #endif