1 +
//
 
2 +
// Copyright (c) 2026 Steve Gerbino
 
3 +
//
 
4 +
// Distributed under the Boost Software License, Version 1.0. (See accompanying
 
5 +
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
6 +
//
 
7 +
// Official repository: https://github.com/cppalliance/corosio
 
8 +
//
 
9 +

 
10 +
#ifndef BOOST_COROSIO_IO_IO_WRITE_STREAM_HPP
 
11 +
#define BOOST_COROSIO_IO_IO_WRITE_STREAM_HPP
 
12 +

 
13 +
#include <boost/corosio/detail/config.hpp>
 
14 +
#include <boost/corosio/io/io_object.hpp>
 
15 +
#include <boost/corosio/io_buffer_param.hpp>
 
16 +
#include <boost/capy/io_result.hpp>
 
17 +
#include <boost/capy/ex/executor_ref.hpp>
 
18 +
#include <boost/capy/ex/io_env.hpp>
 
19 +

 
20 +
#include <coroutine>
 
21 +
#include <cstddef>
 
22 +
#include <stop_token>
 
23 +
#include <system_error>
 
24 +

 
25 +
namespace boost::corosio {
 
26 +

 
27 +
/** Abstract base for streams that support async writes.
 
28 +

 
29 +
    Provides the `write_some` operation via a pure virtual
 
30 +
    `do_write_some` dispatch point. Concrete classes override
 
31 +
    `do_write_some` to route through their implementation.
 
32 +

 
33 +
    Uses virtual inheritance from @ref io_object so that
 
34 +
    @ref io_stream can combine this with @ref io_read_stream
 
35 +
    without duplicating the `io_object` base.
 
36 +

 
37 +
    @par Thread Safety
 
38 +
    Distinct objects: Safe.
 
39 +
    Shared objects: Unsafe.
 
40 +

 
41 +
    @see io_read_stream, io_stream, io_object
 
42 +
*/
 
43 +
class BOOST_COROSIO_DECL io_write_stream : virtual public io_object
 
44 +
{
 
45 +
protected:
 
46 +
    /// Awaitable for async write operations.
 
47 +
    template<class ConstBufferSequence>
 
48 +
    struct write_some_awaitable
 
49 +
    {
 
50 +
        io_write_stream& ios_;
 
51 +
        ConstBufferSequence buffers_;
 
52 +
        std::stop_token token_;
 
53 +
        mutable std::error_code ec_;
 
54 +
        mutable std::size_t bytes_transferred_ = 0;
 
55 +

 
56 +
        write_some_awaitable(
 
57 +
            io_write_stream& ios, ConstBufferSequence buffers) noexcept
 
58 +
            : ios_(ios)
 
59 +
            , buffers_(std::move(buffers))
 
60 +
        {
 
61 +
        }
 
62 +

 
63 +
        bool await_ready() const noexcept
 
64 +
        {
 
65 +
            return token_.stop_requested();
 
66 +
        }
 
67 +

 
68 +
        capy::io_result<std::size_t> await_resume() const noexcept
 
69 +
        {
 
70 +
            if (token_.stop_requested())
 
71 +
                return {make_error_code(std::errc::operation_canceled), 0};
 
72 +
            return {ec_, bytes_transferred_};
 
73 +
        }
 
74 +

 
75 +
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
 
76 +
            -> std::coroutine_handle<>
 
77 +
        {
 
78 +
            token_ = env->stop_token;
 
79 +
            return ios_.do_write_some(
 
80 +
                h, env->executor, buffers_, token_, &ec_, &bytes_transferred_);
 
81 +
        }
 
82 +
    };
 
83 +

 
84 +
    /** Dispatch a write through the concrete implementation.
 
85 +

 
86 +
        @param h Coroutine handle to resume on completion.
 
87 +
        @param ex Executor for dispatching the completion.
 
88 +
        @param buffers Source buffer sequence.
 
89 +
        @param token Stop token for cancellation.
 
90 +
        @param ec Output error code.
 
91 +
        @param bytes Output bytes transferred.
 
92 +

 
93 +
        @return Coroutine handle to resume immediately.
 
94 +
    */
 
95 +
    virtual std::coroutine_handle<> do_write_some(
 
96 +
        std::coroutine_handle<>,
 
97 +
        capy::executor_ref,
 
98 +
        io_buffer_param,
 
99 +
        std::stop_token,
 
100 +
        std::error_code*,
 
101 +
        std::size_t*) = 0;
 
102 +

 
103 +
    io_write_stream() noexcept = default;
 
104 +

 
105 +
    /// Construct from a handle.
 
106 +
    explicit io_write_stream(handle h) noexcept : io_object(std::move(h)) {}
 
107 +

 
108 +
public:
 
109 +
    /** Asynchronously write data to the stream.
 
110 +

 
111 +
        Suspends the calling coroutine and initiates a kernel-level
 
112 +
        write. The coroutine resumes when at least one byte is written,
 
113 +
        an error occurs, or the operation is cancelled.
 
114 +

 
115 +
        @param buffers The buffer sequence containing data to write.
 
116 +

 
117 +
        @return An awaitable yielding `(error_code, std::size_t)`.
 
118 +

 
119 +
        @see io_stream::read_some
 
120 +
    */
 
121 +
    template<capy::ConstBufferSequence CB>
 
122 +
    auto write_some(CB const& buffers)
 
123 +
    {
 
124 +
        return write_some_awaitable<CB>(*this, buffers);
 
125 +
    }
 
126 +
};
 
127 +

 
128 +
} // namespace boost::corosio
 
129 +

 
130 +
#endif