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 Whether the payload is meaningful when `ec` is set is 36   @note Whether the payload is meaningful when `ec` is set is
37   defined by the operation that produced the result. Many I/O 37   defined by the operation that produced the result. Many I/O
38   operations report a meaningful partial result alongside `ec` 38   operations report a meaningful partial result alongside `ec`
39   (for example, the number of bytes transferred before the 39   (for example, the number of bytes transferred before the
40   condition, as with EOF); others leave it unspecified. 40   condition, as with EOF); others leave it unspecified.
41   41  
42   @tparam Ts Ordered payload types following the leading 42   @tparam Ts Ordered payload types following the leading
43   `std::error_code`. 43   `std::error_code`.
44   */ 44   */
45   template<class... Ts> 45   template<class... Ts>
46   struct [[nodiscard]] io_result 46   struct [[nodiscard]] io_result
47   { 47   {
48   /// The error code from the operation. 48   /// The error code from the operation.
49   std::error_code ec; 49   std::error_code ec;
50   50  
51   /// The payload values. Their meaning when `ec` is set is defined 51   /// The payload values. Their meaning when `ec` is set is defined
52   /// by the producing operation (see the class note). 52   /// by the producing operation (see the class note).
53   std::tuple<Ts...> values; 53   std::tuple<Ts...> values;
54   54  
55   /// Construct a default io_result. 55   /// Construct a default io_result.
HITCBC 56   759 io_result() = default; 56   759 io_result() = default;
57   57  
58   /// Construct from an error code and payload values. 58   /// Construct from an error code and payload values.
HITCBC 59   5944 io_result(std::error_code ec_, Ts... ts) 59   5944 io_result(std::error_code ec_, Ts... ts)
HITCBC 60   5944 : ec(ec_) 60   5944 : ec(ec_)
HITCBC 61   5603 , values(std::move(ts)...) 61   5603 , values(std::move(ts)...)
62   { 62   {
HITCBC 63   5944 } 63   5944 }
64   64  
65   /// @cond 65   /// @cond
66   template<std::size_t I> 66   template<std::size_t I>
67   decltype(auto) get() & noexcept 67   decltype(auto) get() & noexcept
68   { 68   {
69   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 69   static_assert(I < 1 + sizeof...(Ts), "index out of range");
70   if constexpr (I == 0) return (ec); 70   if constexpr (I == 0) return (ec);
71   else return std::get<I - 1>(values); 71   else return std::get<I - 1>(values);
72   } 72   }
73   73  
74   template<std::size_t I> 74   template<std::size_t I>
75   decltype(auto) get() const& noexcept 75   decltype(auto) get() const& noexcept
76   { 76   {
77   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 77   static_assert(I < 1 + sizeof...(Ts), "index out of range");
78   if constexpr (I == 0) return (ec); 78   if constexpr (I == 0) return (ec);
79   else return std::get<I - 1>(values); 79   else return std::get<I - 1>(values);
80   } 80   }
81   81  
82   template<std::size_t I> 82   template<std::size_t I>
HITCBC 83   11622 decltype(auto) get() && noexcept 83   11622 decltype(auto) get() && noexcept
84   { 84   {
85   static_assert(I < 1 + sizeof...(Ts), "index out of range"); 85   static_assert(I < 1 + sizeof...(Ts), "index out of range");
HITCBC 86   6267 if constexpr (I == 0) return std::move(ec); 86   6267 if constexpr (I == 0) return std::move(ec);
HITCBC 87   5355 else return std::get<I - 1>(std::move(values)); 87   5355 else return std::get<I - 1>(std::move(values));
88   } 88   }
89   /// @endcond 89   /// @endcond
90   }; 90   };
91   91  
92   /// @cond 92   /// @cond
93   template<std::size_t I, class... Ts> 93   template<std::size_t I, class... Ts>
94   decltype(auto) get(io_result<Ts...>& r) noexcept 94   decltype(auto) get(io_result<Ts...>& r) noexcept
95   { 95   {
96   return r.template get<I>(); 96   return r.template get<I>();
97   } 97   }
98   98  
99   template<std::size_t I, class... Ts> 99   template<std::size_t I, class... Ts>
100   decltype(auto) get(io_result<Ts...> const& r) noexcept 100   decltype(auto) get(io_result<Ts...> const& r) noexcept
101   { 101   {
102   return r.template get<I>(); 102   return r.template get<I>();
103   } 103   }
104   104  
105   template<std::size_t I, class... Ts> 105   template<std::size_t I, class... Ts>
106   decltype(auto) get(io_result<Ts...>&& r) noexcept 106   decltype(auto) get(io_result<Ts...>&& r) noexcept
107   { 107   {
108   return std::move(r).template get<I>(); 108   return std::move(r).template get<I>();
109   } 109   }
110   /// @endcond 110   /// @endcond
111   111  
112   } // namespace capy 112   } // namespace capy
113   } // namespace boost 113   } // namespace boost
114   114  
115   // Tuple protocol for structured bindings 115   // Tuple protocol for structured bindings
116   namespace std { 116   namespace std {
117   117  
118   template<class... Ts> 118   template<class... Ts>
119   struct tuple_size<boost::capy::io_result<Ts...>> 119   struct tuple_size<boost::capy::io_result<Ts...>>
120   : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {}; 120   : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {};
121   121  
122   template<class... Ts> 122   template<class... Ts>
123   struct tuple_element<0, boost::capy::io_result<Ts...>> 123   struct tuple_element<0, boost::capy::io_result<Ts...>>
124   { 124   {
125   using type = std::error_code; 125   using type = std::error_code;
126   }; 126   };
127   127  
128   template<std::size_t I, class... Ts> 128   template<std::size_t I, class... Ts>
129   struct tuple_element<I, boost::capy::io_result<Ts...>> 129   struct tuple_element<I, boost::capy::io_result<Ts...>>
130   { 130   {
131   using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>; 131   using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>;
132   }; 132   };
133   133  
134   } // namespace std 134   } // namespace std
135   135  
136   #endif // BOOST_CAPY_IO_RESULT_HPP 136   #endif // BOOST_CAPY_IO_RESULT_HPP