100.00% Lines (7/7) 100.00% Functions (4/4)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2026 Steve Gerbino 3   // Copyright (c) 2026 Steve Gerbino
  4 + // Copyright (c) 2026 Michael Vandeberg
4   // 5   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 6   // Distributed under the Boost Software License, Version 1.0. (See accompanying
6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 8   //
8   // Official repository: https://github.com/cppalliance/corosio 9   // Official repository: https://github.com/cppalliance/corosio
9   // 10   //
10   11  
11   #ifndef BOOST_COROSIO_IO_IO_STREAM_HPP 12   #ifndef BOOST_COROSIO_IO_IO_STREAM_HPP
12   #define BOOST_COROSIO_IO_IO_STREAM_HPP 13   #define BOOST_COROSIO_IO_IO_STREAM_HPP
13   14  
14   #include <boost/corosio/detail/config.hpp> 15   #include <boost/corosio/detail/config.hpp>
15   #include <boost/corosio/io/io_read_stream.hpp> 16   #include <boost/corosio/io/io_read_stream.hpp>
16   #include <boost/corosio/io/io_write_stream.hpp> 17   #include <boost/corosio/io/io_write_stream.hpp>
17   #include <boost/corosio/detail/buffer_param.hpp> 18   #include <boost/corosio/detail/buffer_param.hpp>
18   #include <boost/capy/ex/executor_ref.hpp> 19   #include <boost/capy/ex/executor_ref.hpp>
19   20  
20   #include <coroutine> 21   #include <coroutine>
21   #include <cstddef> 22   #include <cstddef>
22   #include <stop_token> 23   #include <stop_token>
23   #include <system_error> 24   #include <system_error>
24   25  
25   namespace boost::corosio { 26   namespace boost::corosio {
26   27  
27   /** Platform stream with read/write operations. 28   /** Platform stream with read/write operations.
28   29  
29   Combines @ref io_read_stream and @ref io_write_stream into 30   Combines @ref io_read_stream and @ref io_write_stream into
30   a single bidirectional stream. The `read_some` and `write_some` 31   a single bidirectional stream. The `read_some` and `write_some`
31   operations are inherited from the base classes and dispatch 32   operations are inherited from the base classes and dispatch
32   through `do_read_some` / `do_write_some`, which this class 33   through `do_read_some` / `do_write_some`, which this class
33   implements by forwarding to the platform `implementation`. 34   implements by forwarding to the platform `implementation`.
34   35  
35   The implementation hierarchy stays linear (no diamond): 36   The implementation hierarchy stays linear (no diamond):
36   `io_object::implementation` -> `io_stream::implementation` 37   `io_object::implementation` -> `io_stream::implementation`
37   -> `tcp_socket::implementation` -> backend impl. 38   -> `tcp_socket::implementation` -> backend impl.
38   39  
39   @par Semantics 40   @par Semantics
40   Concrete classes wrap direct platform I/O completed by the kernel. 41   Concrete classes wrap direct platform I/O completed by the kernel.
41   Functions taking `io_stream&` signal "platform implementation 42   Functions taking `io_stream&` signal "platform implementation
42   required" - use this when you need actual kernel I/O rather than 43   required" - use this when you need actual kernel I/O rather than
43   a mock or test double. 44   a mock or test double.
44   45  
45   For generic stream algorithms that work with test mocks, 46   For generic stream algorithms that work with test mocks,
46   use `template<capy::Stream S>` instead of `io_stream&`. 47   use `template<capy::Stream S>` instead of `io_stream&`.
47   48  
48   @par Thread Safety 49   @par Thread Safety
49   Distinct objects: Safe. 50   Distinct objects: Safe.
50   Shared objects: Unsafe. All calls to a single stream must be made 51   Shared objects: Unsafe. All calls to a single stream must be made
51   from the same implicit or explicit serialization context. 52   from the same implicit or explicit serialization context.
52   53  
53   @par Example 54   @par Example
54 - @code 55 + @par !example io_stream
55 - // Read until buffer full or EOF  
56 - capy::task<> read_all( io_stream& stream, std::span<char> buf )  
57 - {  
58 - std::size_t total = 0;  
59 - while( total < buf.size() )  
60 - {  
61 - auto [ec, n] = co_await stream.read_some(  
62 - capy::mutable_buffer( buf.data() + total, buf.size() - total ) );  
63 - if( ec == capy::cond::eof )  
64 - break;  
65 - if( ec )  
66 - throw std::system_error( ec );  
67 - total += n;  
68 - }  
69 - }  
70 - @endcode  
71   56  
72   @see io_read_stream, io_write_stream, tcp_socket 57   @see io_read_stream, io_write_stream, tcp_socket
73   */ 58   */
74   class BOOST_COROSIO_DECL io_stream 59   class BOOST_COROSIO_DECL io_stream
75   : public io_read_stream 60   : public io_read_stream
76   , public io_write_stream 61   , public io_write_stream
77   { 62   {
78   public: 63   public:
79   /** Platform-specific stream implementation interface. 64   /** Platform-specific stream implementation interface.
80   65  
81   Derived classes implement this interface to provide kernel-level 66   Derived classes implement this interface to provide kernel-level
82   read and write operations for each supported platform (IOCP, 67   read and write operations for each supported platform (IOCP,
83   epoll, kqueue, io_uring). 68   epoll, kqueue, io_uring).
84   */ 69   */
85   struct implementation : io_object::implementation 70   struct implementation : io_object::implementation
86   { 71   {
87   /// Initiate platform read operation. 72   /// Initiate platform read operation.
88   virtual std::coroutine_handle<> read_some( 73   virtual std::coroutine_handle<> read_some(
89   std::coroutine_handle<>, 74   std::coroutine_handle<>,
90   capy::executor_ref, 75   capy::executor_ref,
91   buffer_param, 76   buffer_param,
92   std::stop_token, 77   std::stop_token,
93   std::error_code*, 78   std::error_code*,
94   std::size_t*) = 0; 79   std::size_t*) = 0;
95   80  
96   /// Initiate platform write operation. 81   /// Initiate platform write operation.
97   virtual std::coroutine_handle<> write_some( 82   virtual std::coroutine_handle<> write_some(
98   std::coroutine_handle<>, 83   std::coroutine_handle<>,
99   capy::executor_ref, 84   capy::executor_ref,
100   buffer_param, 85   buffer_param,
101   std::stop_token, 86   std::stop_token,
102   std::error_code*, 87   std::error_code*,
103   std::size_t*) = 0; 88   std::size_t*) = 0;
104   }; 89   };
105   90  
106   protected: 91   protected:
HITCBC 107   14289 io_stream() noexcept = default; 92   14145 io_stream() noexcept = default;
108   93  
109   /// Construct stream from a handle. 94   /// Construct stream from a handle.
110   explicit io_stream(handle h) noexcept : io_object(std::move(h)) {} 95   explicit io_stream(handle h) noexcept : io_object(std::move(h)) {}
111   96  
112   /// Dispatch read through implementation vtable. 97   /// Dispatch read through implementation vtable.
HITCBC 113   197548 std::coroutine_handle<> do_read_some( 98   197170 std::coroutine_handle<> do_read_some(
114   std::coroutine_handle<> h, 99   std::coroutine_handle<> h,
115   capy::executor_ref ex, 100   capy::executor_ref ex,
116   buffer_param buffers, 101   buffer_param buffers,
117   std::stop_token token, 102   std::stop_token token,
118   std::error_code* ec, 103   std::error_code* ec,
119   std::size_t* bytes) override 104   std::size_t* bytes) override
120   { 105   {
HITCBC 121   197548 return get().read_some(h, ex, buffers, std::move(token), ec, bytes); 106   197170 return get().read_some(h, ex, buffers, std::move(token), ec, bytes);
122   } 107   }
123   108  
124   /// Dispatch write through implementation vtable. 109   /// Dispatch write through implementation vtable.
HITCBC 125   196803 std::coroutine_handle<> do_write_some( 110   196427 std::coroutine_handle<> do_write_some(
126   std::coroutine_handle<> h, 111   std::coroutine_handle<> h,
127   capy::executor_ref ex, 112   capy::executor_ref ex,
128   buffer_param buffers, 113   buffer_param buffers,
129   std::stop_token token, 114   std::stop_token token,
130   std::error_code* ec, 115   std::error_code* ec,
131   std::size_t* bytes) override 116   std::size_t* bytes) override
132   { 117   {
HITCBC 133   196803 return get().write_some(h, ex, buffers, std::move(token), ec, bytes); 118   196427 return get().write_some(h, ex, buffers, std::move(token), ec, bytes);
134   } 119   }
135   120  
136   private: 121   private:
137   /// Return implementation downcasted to stream interface. 122   /// Return implementation downcasted to stream interface.
HITCBC 138   394351 implementation& get() const noexcept 123   393597 implementation& get() const noexcept
139   { 124   {
HITCBC 140   394351 return *static_cast<implementation*>(h_.get()); 125   393597 return *static_cast<implementation*>(h_.get());
141   } 126   }
142   }; 127   };
143   128  
144   } // namespace boost::corosio 129   } // namespace boost::corosio
145   130  
146   #endif 131   #endif