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

12  

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

15  

16  
#include <system_error>
16  
#include <system_error>
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  
namespace detail {
23  
namespace detail {
24  

24  

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

27  

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

30  

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

33  

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

38  

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

44  

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

50  

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

57  

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

63  

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

69  

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

73  

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

82  

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

89  

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

93  

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

102  

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

113  

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

123  

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

127  

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

136  

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

140  

141  
#endif
141  
#endif