1 +
//
 
2 +
// Copyright (c) 2026 Steve Gerbino
 
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_DETAIL_IO_RESULT_COMBINATORS_HPP
 
11 +
#define BOOST_CAPY_DETAIL_IO_RESULT_COMBINATORS_HPP
 
12 +

 
13 +
#include <boost/capy/concept/io_awaitable.hpp>
 
14 +
#include <boost/capy/io_result.hpp>
 
15 +

 
16 +
#include <system_error>
 
17 +
#include <tuple>
 
18 +
#include <type_traits>
 
19 +
#include <utility>
 
20 +

 
21 +
namespace boost {
 
22 +
namespace capy {
 
23 +
namespace detail {
 
24 +

 
25 +
template<typename T>
 
26 +
struct is_io_result : std::false_type {};
 
27 +

 
28 +
template<typename... Args>
 
29 +
struct is_io_result<io_result<Args...>> : std::true_type {};
 
30 +

 
31 +
template<typename T>
 
32 +
inline constexpr bool is_io_result_v = is_io_result<T>::value;
 
33 +

 
34 +
/// True when every awaitable in the pack returns an io_result.
 
35 +
template<typename... As>
 
36 +
concept all_io_result_awaitables =
 
37 +
    (is_io_result_v<awaitable_result_t<As>> && ...);
 
38 +

 
39 +
/// True when the io_result-aware when_all overload should be used.
 
40 +
template<typename... As>
 
41 +
concept when_all_io_eligible =
 
42 +
    (sizeof...(As) > 0)
 
43 +
    && all_io_result_awaitables<As...>;
 
44 +

 
45 +
/// True when the io_result-aware when_any overload should be used.
 
46 +
template<typename... As>
 
47 +
concept when_any_io_eligible =
 
48 +
    (sizeof...(As) > 0)
 
49 +
    && all_io_result_awaitables<As...>;
 
50 +

 
51 +
/// Map an io_result specialization to its contributed payload type.
 
52 +
///
 
53 +
///   io_result<T>       -> T            (unwrap single)
 
54 +
///   io_result<Ts...>   -> tuple<Ts...> (zero, two, or more)
 
55 +
template<typename IoResult>
 
56 +
struct io_result_payload;
 
57 +

 
58 +
template<typename T>
 
59 +
struct io_result_payload<io_result<T>>
 
60 +
{
 
61 +
    using type = T;
 
62 +
};
 
63 +

 
64 +
template<typename... Ts>
 
65 +
struct io_result_payload<io_result<Ts...>>
 
66 +
{
 
67 +
    using type = std::tuple<Ts...>;
 
68 +
};
 
69 +

 
70 +
template<typename IoResult>
 
71 +
using io_result_payload_t =
 
72 +
    typename io_result_payload<IoResult>::type;
 
73 +

 
74 +
/// Extract the payload value(s) from an io_result,
 
75 +
/// matching the type produced by io_result_payload_t.
 
76 +
template<typename T>
 
77 +
T
 
78 +
extract_io_payload(io_result<T>&& r)
 
79 +
{
 
80 +
    return std::get<0>(std::move(r.values));
 
81 +
}
 
82 +

 
83 +
template<typename... Ts>
 
84 +
std::tuple<Ts...>
 
85 +
extract_io_payload(io_result<Ts...>&& r)
 
86 +
{
 
87 +
    return std::move(r.values);
 
88 +
}
 
89 +

 
90 +
/// Reconstruct a success io_result from a payload extracted by when_any.
 
91 +
template<typename IoResult>
 
92 +
struct io_result_from_payload;
 
93 +

 
94 +
template<typename T>
 
95 +
struct io_result_from_payload<io_result<T>>
 
96 +
{
 
97 +
    static io_result<T> apply(T t)
 
98 +
    {
 
99 +
        return io_result<T>{{}, std::move(t)};
 
100 +
    }
 
101 +
};
 
102 +

 
103 +
template<typename... Ts>
 
104 +
struct io_result_from_payload<io_result<Ts...>>
 
105 +
{
 
106 +
    static io_result<Ts...> apply(std::tuple<Ts...> t)
 
107 +
    {
 
108 +
        return std::apply([](auto&&... args) {
 
109 +
            return io_result<Ts...>{{}, std::move(args)...};
 
110 +
        }, std::move(t));
 
111 +
    }
 
112 +
};
 
113 +

 
114 +
/// Build the outer io_result for when_all from a tuple of child io_results.
 
115 +
template<typename ResultType, typename Tuple, std::size_t... Is>
 
116 +
ResultType
 
117 +
build_when_all_io_result_impl(Tuple&& results, std::index_sequence<Is...>)
 
118 +
{
 
119 +
    std::error_code ec;
 
120 +
    (void)((std::get<Is>(results).ec && !ec
 
121 +
        ? (ec = std::get<Is>(results).ec, true)
 
122 +
        : false) || ...);
 
123 +

 
124 +
    return ResultType{ec, extract_io_payload(
 
125 +
        std::move(std::get<Is>(results)))...};
 
126 +
}
 
127 +

 
128 +
template<typename ResultType, typename... IoResults>
 
129 +
ResultType
 
130 +
build_when_all_io_result(std::tuple<IoResults...>&& results)
 
131 +
{
 
132 +
    return build_when_all_io_result_impl<ResultType>(
 
133 +
        std::move(results),
 
134 +
        std::index_sequence_for<IoResults...>{});
 
135 +
}
 
136 +

 
137 +
} // namespace detail
 
138 +
} // namespace capy
 
139 +
} // namespace boost
 
140 +

 
141 +
#endif