100.00% Lines (8/8) 100.00% Functions (3/3)
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   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #ifndef BOOST_CAPY_IO_RESULT_HPP 10   #ifndef BOOST_CAPY_IO_RESULT_HPP
11   #define BOOST_CAPY_IO_RESULT_HPP 11   #define BOOST_CAPY_IO_RESULT_HPP
12   12  
13   #include <boost/capy/detail/config.hpp> 13   #include <boost/capy/detail/config.hpp>
14   #include <system_error> 14   #include <system_error>
15   15  
16   #include <cstddef> 16   #include <cstddef>
17   #include <tuple> 17   #include <tuple>
18   #include <type_traits> 18   #include <type_traits>
19   #include <utility> 19   #include <utility>
20   20  
21   namespace boost { 21   namespace boost {
22   namespace capy { 22   namespace capy {
23   23  
24   /** Result type for asynchronous I/O operations. 24   /** Result type for asynchronous I/O operations.
25   25  
26   This template provides a unified result type for async operations, 26   This template provides a unified result type for async operations,
27   always containing a `std::error_code` plus optional additional 27   always containing a `std::error_code` plus optional additional
28   values. It supports structured bindings via the tuple protocol. 28   values. It supports structured bindings via the tuple protocol.
29   29  
30   @par Example 30   @par Example
31   @code 31   @code
32   auto [ec, n] = co_await s.read_some(buf); 32   auto [ec, n] = co_await s.read_some(buf);
33   if (ec) { ... } 33   if (ec) { ... }
34   @endcode 34   @endcode
35   35  
36 - @note Payload members are only meaningful when 36 + @note Whether the payload is meaningful when `ec` is set is
37 - `ec` does not indicate an error. 37 + defined by the operation that produced the result. Many I/O
  38 + operations report a meaningful partial result alongside `ec`
  39 + (for example, the number of bytes transferred before the
  40 + condition, as with EOF); others leave it unspecified.
38   41  
39   @tparam Ts Ordered payload types following the leading 42   @tparam Ts Ordered payload types following the leading
40   `std::error_code`. 43   `std::error_code`.
41   */ 44   */
42   template<class... Ts> 45   template<class... Ts>
43   struct [[nodiscard]] io_result 46   struct [[nodiscard]] io_result
44   { 47   {
45   /// The error code from the operation. 48   /// The error code from the operation.
46   std::error_code ec; 49   std::error_code ec;
47   50  
48 - /// The payload values. Unspecified when `ec` is set. 51 + /// The payload values. Their meaning when `ec` is set is defined
  52 + /// by the producing operation (see the class note).
49   std::tuple<Ts...> values; 53   std::tuple<Ts...> values;
50   54  
51   /// Construct a default io_result. 55   /// Construct a default io_result.
HITCBC 52   759 io_result() = default; 56   759 io_result() = default;
53   57  
54   /// Construct from an error code and payload values. 58   /// Construct from an error code and payload values.
HITCBC 55   5932 io_result(std::error_code ec_, Ts... ts) 59   5944 io_result(std::error_code ec_, Ts... ts)
HITCBC 56   5932 : ec(ec_) 60   5944 : ec(ec_)
HITCBC 57   5591 , values(std::move(ts)...) 61   5603 , values(std::move(ts)...)
58   { 62   {
HITCBC 59   5932 } 63   5944 }
60   64  
61   /// @cond 65   /// @cond
62   template<std::size_t I> 66   template<std::size_t I>
63   decltype(auto) get() & noexcept 67   decltype(auto) get() & noexcept
64   { 68   {
65   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 69   static_assert(I < 1 + sizeof...(Ts), "index out of range");
66   if constexpr (I == 0) return (ec); 70   if constexpr (I == 0) return (ec);
67   else return std::get<I - 1>(values); 71   else return std::get<I - 1>(values);
68   } 72   }
69   73  
70   template<std::size_t I> 74   template<std::size_t I>
71   decltype(auto) get() const& noexcept 75   decltype(auto) get() const& noexcept
72   { 76   {
73   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 77   static_assert(I < 1 + sizeof...(Ts), "index out of range");
74   if constexpr (I == 0) return (ec); 78   if constexpr (I == 0) return (ec);
75   else return std::get<I - 1>(values); 79   else return std::get<I - 1>(values);
76   } 80   }
77   81  
78   template<std::size_t I> 82   template<std::size_t I>
HITCBC 79   11598 decltype(auto) get() && noexcept 83   11622 decltype(auto) get() && noexcept
80   { 84   {
81   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 85   static_assert(I < 1 + sizeof...(Ts), "index out of range");
HITCBC 82   6255 if constexpr (I == 0) return std::move(ec); 86   6267 if constexpr (I == 0) return std::move(ec);
HITCBC 83   5343 else return std::get<I - 1>(std::move(values)); 87   5355 else return std::get<I - 1>(std::move(values));
84   } 88   }
85   /// @endcond 89   /// @endcond
86   }; 90   };
87   91  
88   /// @cond 92   /// @cond
89   template<std::size_t I, class... Ts> 93   template<std::size_t I, class... Ts>
90   decltype(auto) get(io_result<Ts...>& r) noexcept 94   decltype(auto) get(io_result<Ts...>& r) noexcept
91   { 95   {
92   return r.template get<I>(); 96   return r.template get<I>();
93   } 97   }
94   98  
95   template<std::size_t I, class... Ts> 99   template<std::size_t I, class... Ts>
96   decltype(auto) get(io_result<Ts...> const& r) noexcept 100   decltype(auto) get(io_result<Ts...> const& r) noexcept
97   { 101   {
98   return r.template get<I>(); 102   return r.template get<I>();
99   } 103   }
100   104  
101   template<std::size_t I, class... Ts> 105   template<std::size_t I, class... Ts>
102   decltype(auto) get(io_result<Ts...>&& r) noexcept 106   decltype(auto) get(io_result<Ts...>&& r) noexcept
103   { 107   {
104   return std::move(r).template get<I>(); 108   return std::move(r).template get<I>();
105   } 109   }
106   /// @endcond 110   /// @endcond
107   111  
108   } // namespace capy 112   } // namespace capy
109   } // namespace boost 113   } // namespace boost
110   114  
111   // Tuple protocol for structured bindings 115   // Tuple protocol for structured bindings
112   namespace std { 116   namespace std {
113   117  
114   template<class... Ts> 118   template<class... Ts>
115   struct tuple_size<boost::capy::io_result<Ts...>> 119   struct tuple_size<boost::capy::io_result<Ts...>>
116   : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {}; 120   : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {};
117   121  
118   template<class... Ts> 122   template<class... Ts>
119   struct tuple_element<0, boost::capy::io_result<Ts...>> 123   struct tuple_element<0, boost::capy::io_result<Ts...>>
120   { 124   {
121   using type = std::error_code; 125   using type = std::error_code;
122   }; 126   };
123   127  
124   template<std::size_t I, class... Ts> 128   template<std::size_t I, class... Ts>
125   struct tuple_element<I, boost::capy::io_result<Ts...>> 129   struct tuple_element<I, boost::capy::io_result<Ts...>>
126   { 130   {
127   using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>; 131   using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>;
128   }; 132   };
129   133  
130   } // namespace std 134   } // namespace std
131   135  
132   #endif // BOOST_CAPY_IO_RESULT_HPP 136   #endif // BOOST_CAPY_IO_RESULT_HPP