TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
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/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_IO_RESULT_HPP
11 : #define BOOST_CAPY_IO_RESULT_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <system_error>
15 :
16 : #include <cstddef>
17 : #include <tuple>
18 : #include <type_traits>
19 : #include <utility>
20 :
21 : namespace boost {
22 : namespace capy {
23 :
24 : /** Result type for asynchronous I/O operations.
25 :
26 : This template provides a unified result type for async operations,
27 : always containing a `std::error_code` plus optional additional
28 : values. It supports structured bindings via the tuple protocol.
29 :
30 : @par Example
31 : @code
32 : auto [ec, n] = co_await s.read_some(buf);
33 : if (ec) { ... }
34 : @endcode
35 :
36 : @note Whether the payload is meaningful when `ec` is set is
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.
41 :
42 : @tparam Ts Ordered payload types following the leading
43 : `std::error_code`.
44 : */
45 : template<class... Ts>
46 : struct [[nodiscard]] io_result
47 : {
48 : /// The error code from the operation.
49 : std::error_code ec;
50 :
51 : /// The payload values. Their meaning when `ec` is set is defined
52 : /// by the producing operation (see the class note).
53 : std::tuple<Ts...> values;
54 :
55 : /// Construct a default io_result.
56 HIT 759 : io_result() = default;
57 :
58 : /// Construct from an error code and payload values.
59 5944 : io_result(std::error_code ec_, Ts... ts)
60 5944 : : ec(ec_)
61 5603 : , values(std::move(ts)...)
62 : {
63 5944 : }
64 :
65 : /// @cond
66 : template<std::size_t I>
67 : decltype(auto) get() & noexcept
68 : {
69 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
70 : if constexpr (I == 0) return (ec);
71 : else return std::get<I - 1>(values);
72 : }
73 :
74 : template<std::size_t I>
75 : decltype(auto) get() const& noexcept
76 : {
77 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
78 : if constexpr (I == 0) return (ec);
79 : else return std::get<I - 1>(values);
80 : }
81 :
82 : template<std::size_t I>
83 11622 : decltype(auto) get() && noexcept
84 : {
85 : static_assert(I < 1 + sizeof...(Ts), "index out of range");
86 6267 : if constexpr (I == 0) return std::move(ec);
87 5355 : else return std::get<I - 1>(std::move(values));
88 : }
89 : /// @endcond
90 : };
91 :
92 : /// @cond
93 : template<std::size_t I, class... Ts>
94 : decltype(auto) get(io_result<Ts...>& r) noexcept
95 : {
96 : return r.template get<I>();
97 : }
98 :
99 : template<std::size_t I, class... Ts>
100 : decltype(auto) get(io_result<Ts...> const& r) noexcept
101 : {
102 : return r.template get<I>();
103 : }
104 :
105 : template<std::size_t I, class... Ts>
106 : decltype(auto) get(io_result<Ts...>&& r) noexcept
107 : {
108 : return std::move(r).template get<I>();
109 : }
110 : /// @endcond
111 :
112 : } // namespace capy
113 : } // namespace boost
114 :
115 : // Tuple protocol for structured bindings
116 : namespace std {
117 :
118 : template<class... Ts>
119 : struct tuple_size<boost::capy::io_result<Ts...>>
120 : : std::integral_constant<std::size_t, 1 + sizeof...(Ts)> {};
121 :
122 : template<class... Ts>
123 : struct tuple_element<0, boost::capy::io_result<Ts...>>
124 : {
125 : using type = std::error_code;
126 : };
127 :
128 : template<std::size_t I, class... Ts>
129 : struct tuple_element<I, boost::capy::io_result<Ts...>>
130 : {
131 : using type = std::tuple_element_t<I - 1, std::tuple<Ts...>>;
132 : };
133 :
134 : } // namespace std
135 :
136 : #endif // BOOST_CAPY_IO_RESULT_HPP
|