100.00% Lines (15/15) 100.00% Functions (4/4)
TLA Baseline Branch
Line Hits Code Line Hits Code
  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
HITGNC   78 + 67 extract_io_payload(io_result<T>&& r)
  79 + {
HITGNC   80 + 67 return std::get<0>(std::move(r.values));
  81 + }
  82 +
  83 + template<typename... Ts>
  84 + std::tuple<Ts...>
HITGNC   85 + 38 extract_io_payload(io_result<Ts...>&& r)
  86 + {
HITGNC   87 + 38 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
HITGNC   117 + 36 build_when_all_io_result_impl(Tuple&& results, std::index_sequence<Is...>)
  118 + {
HITGNC   119 + 36 std::error_code ec;
HITGNC   120 + 71 (void)((std::get<Is>(results).ec && !ec
HITGNC   121 + 20 ? (ec = std::get<Is>(results).ec, true)
HITGNC   122 + 15 : false) || ...);
  123 +
HITGNC   124 + 37 return ResultType{ec, extract_io_payload(
HITGNC   125 + 106 std::move(std::get<Is>(results)))...};
HITGNC   126 + 17 }
  127 +
  128 + template<typename ResultType, typename... IoResults>
  129 + ResultType
HITGNC   130 + 36 build_when_all_io_result(std::tuple<IoResults...>&& results)
  131 + {
  132 + return build_when_all_io_result_impl<ResultType>(
HITGNC   133 + 36 std::move(results),
HITGNC   134 + 36 std::index_sequence_for<IoResults...>{});
  135 + }
  136 +
  137 + } // namespace detail
  138 + } // namespace capy
  139 + } // namespace boost
  140 +
  141 + #endif