TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // 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 : //
8 : // Official repository: https://github.com/cppalliance/capy
9 : //
10 :
11 : #ifndef BOOST_CAPY_IO_RESULT_HPP
12 : #define BOOST_CAPY_IO_RESULT_HPP
13 :
14 : #include <boost/capy/detail/config.hpp>
15 : #include <system_error>
16 :
17 : #include <cstddef>
18 : #include <tuple>
19 : #include <type_traits>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace capy {
24 :
25 : /** Bundles an error code with optional payload values, exposed via the tuple protocol.
26 :
27 : This template provides a unified result type for async operations,
28 : always containing a `std::error_code` plus optional additional
29 : values. It supports structured bindings via the tuple protocol.
30 :
31 : @par Example
32 : @code
33 : auto [ec, n] = co_await s.read_some(buf);
34 : if (ec) { ... }
35 : @endcode
36 :
37 : @note Whether the payload is meaningful when `ec` is set is
38 : defined by the operation that produced the result. Many I/O
39 : operations report a meaningful partial result alongside `ec`
40 : (for example, the number of bytes transferred before the
41 : condition, as with EOF). Others leave it unspecified.
42 :
43 : @tparam Ts Ordered payload types following the leading
44 : `std::error_code`.
45 : */
46 : template<class... Ts>
47 : struct [[nodiscard]] io_result
48 : {
49 : /// The error code from the operation.
50 : std::error_code ec;
51 :
52 : /// The payload values. Their meaning when `ec` is set is defined
53 : /// by the producing operation (see the class note).
54 : std::tuple<Ts...> values;
55 :
56 : /// Construct a default io_result.
57 HIT 130 : io_result() = default;
58 :
59 : /** Construct from an error code and payload values.
60 :
61 : @param ec_ The error code for the operation.
62 :
63 : @param ts The payload values, in declaration order.
64 : */
65 1983 : io_result(std::error_code ec_, Ts... ts)
66 1983 : : ec(ec_)
67 1755 : , values(std::move(ts)...)
68 : {
69 1983 : }
70 :
71 : /** Return the `I`-th element of the tuple protocol.
72 :
73 : Index 0 is @ref ec; index `I` for `I > 0` is the `I - 1`-th
74 : payload value. This is the accessor structured bindings use.
75 :
76 : @tparam I The element index. Must be less than
77 : `1 + sizeof...(Ts)`.
78 :
79 : @return A reference to the element.
80 : */
81 : template<std::size_t I>
82 : decltype(auto) get() & noexcept
83 : {
84 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
85 : if constexpr (I == 0) return (ec);
86 : else return std::get<I - 1>(values);
87 : }
88 :
89 : /** Return the `I`-th element of the tuple protocol.
90 :
91 : Index 0 is @ref ec; index `I` for `I > 0` is the `I - 1`-th
92 : payload value. This is the accessor structured bindings use.
93 :
94 : @tparam I The element index. Must be less than
95 : `1 + sizeof...(Ts)`.
96 :
97 : @return A const reference to the element.
98 : */
99 : template<std::size_t I>
100 : decltype(auto) get() const& noexcept
101 : {
102 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
103 : if constexpr (I == 0) return (ec);
104 : else return std::get<I - 1>(values);
105 : }
106 :
107 : /** Return the `I`-th element of the tuple protocol, moved.
108 :
109 : Index 0 is @ref ec; index `I` for `I > 0` is the `I - 1`-th
110 : payload value.
111 :
112 : @tparam I The element index. Must be less than
113 : `1 + sizeof...(Ts)`.
114 :
115 : @return An rvalue reference to the element, suitable for moving
116 : out of the result.
117 : */
118 : template<std::size_t I>
119 3116 : decltype(auto) get() && noexcept
120 : {
121 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
122 1644 : if constexpr (I == 0) return std::move(ec);
123 1472 : else return std::get<I - 1>(std::move(values));
124 : }
125 : };
126 :
127 : /** Return the `I`-th element of the tuple protocol.
128 :
129 : @tparam I The element index. Must be less than
130 : `1 + sizeof...(Ts)`.
131 :
132 : @param r The result to access.
133 :
134 : @return A reference to the element.
135 : */
136 : template<std::size_t I, class... Ts>
137 : decltype(auto) get(io_result<Ts...>& r) noexcept
138 : {
139 : return r.template get<I>();
140 : }
141 :
142 : /** Return the `I`-th element of the tuple protocol.
143 :
144 : @tparam I The element index. Must be less than
145 : `1 + sizeof...(Ts)`.
146 :
147 : @param r The result to access.
148 :
149 : @return A const reference to the element.
150 : */
151 : template<std::size_t I, class... Ts>
152 : decltype(auto) get(io_result<Ts...> const& r) noexcept
153 : {
154 : return r.template get<I>();
155 : }
156 :
157 : /** Return the `I`-th element of the tuple protocol, moved.
158 :
159 : @tparam I The element index. Must be less than
160 : `1 + sizeof...(Ts)`.
161 :
162 : @param r The result to access.
163 :
164 : @return An rvalue reference to the element, suitable for moving out
165 : of `r`.
166 : */
167 : template<std::size_t I, class... Ts>
168 : decltype(auto) get(io_result<Ts...>&& r) noexcept
169 : {
170 : return std::move(r).template get<I>();
171 : }
172 :
173 : } // namespace capy
174 : } // namespace boost
175 :
176 : // Tuple protocol for structured bindings
177 : namespace std {
178 :
179 : template<class... Ts>
180 : struct tuple_size<boost::capy::io_result<Ts...>>
181 : : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {};
182 :
183 : template<class... Ts>
184 : struct tuple_element<0, boost::capy::io_result<Ts...>>
185 : {
186 : using type = std::error_code;
187 : };
188 :
189 : template<std::size_t I, class... Ts>
190 : struct tuple_element<I, boost::capy::io_result<Ts...>>
191 : {
192 : using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>;
193 : };
194 :
195 : } // namespace std
196 :
197 : #endif // BOOST_CAPY_IO_RESULT_HPP
|