File indexing completed on 2025-12-16 09:44:27
0001
0002
0003
0004
0005 #ifndef BOOST_COBALT_RESULT_HPP
0006 #define BOOST_COBALT_RESULT_HPP
0007
0008 #include <boost/cobalt/concepts.hpp>
0009
0010 #include <boost/core/no_exceptions_support.hpp>
0011 #include <boost/system/result.hpp>
0012
0013 namespace boost::cobalt
0014 {
0015
0016
0017 namespace detail
0018 {
0019
0020 template<typename T>
0021 concept result_error =
0022 requires (const T & t, const source_location & loc)
0023 {
0024 system::throw_exception_from_error(t, loc);
0025 }
0026 ||
0027 requires (const T & t, const source_location & loc)
0028 {
0029 throw_exception_from_error(t, loc);
0030 }
0031 ;
0032
0033 }
0034
0035 inline constexpr auto interpret_as_result(std::tuple<> &&)
0036 {
0037 return system::result<void>();
0038 }
0039
0040 template<typename Arg>
0041 auto interpret_as_result(std::tuple<Arg> && args)
0042 {
0043 if constexpr (detail::result_error<Arg>)
0044 {
0045 if (std::get<0>(args))
0046 return system::result<void, Arg>(system::in_place_error, std::get<0>(args));
0047 else
0048 return system::result<void, Arg>(system::in_place_value);
0049 }
0050
0051 else
0052 return system::result<Arg>(std::move(std::get<0>(args)));
0053 }
0054
0055 template<typename First, typename ... Args>
0056 requires (!detail::result_error<First> && sizeof...(Args) > 0u)
0057 auto interpret_as_result(std::tuple<First, Args...> && args) -> system::result<std::tuple<First, Args...>>
0058 {
0059 return std::move(args);
0060 }
0061
0062 template<detail::result_error Error, typename ... Args>
0063 requires (sizeof...(Args) > 1u)
0064 auto interpret_as_result(std::tuple<Error, Args...> && args) -> system::result<std::tuple<Args...>, Error>
0065 {
0066 if (std::get<0>(args))
0067 return {system::in_place_error, std::move(std::get<0>(args))};
0068 return {
0069 system::in_place_value,
0070 std::apply([](auto, auto && ... rest) {return std::make_tuple(std::move(rest)...);}, std::move(args))
0071 };
0072 }
0073
0074 template<detail::result_error Error, typename Arg>
0075 auto interpret_as_result(std::tuple<Error, Arg> && args) -> system::result<Arg, Error>
0076 {
0077 if (std::get<0>(args))
0078 return {system::in_place_error, std::get<0>(args)};
0079
0080 return {system::in_place_value, std::get<1>(std::move(args))};
0081 }
0082
0083 struct as_result_tag {};
0084 struct as_tuple_tag {};
0085
0086 template<awaitable_type Aw>
0087 struct as_result_t
0088 {
0089 as_result_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
0090
0091 template<typename Aw_>
0092 requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
0093 as_result_t(Aw_ && aw) : aw_(std::forward<Aw_>(aw).operator co_await()) {}
0094
0095 template<typename Aw_>
0096 requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
0097 as_result_t(Aw_ && aw) : aw_(operator co_await(std::forward<Aw_>(aw))) {}
0098
0099 bool await_ready() { return aw_.await_ready();}
0100 template<typename T>
0101 auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
0102
0103 auto await_resume()
0104 {
0105 if constexpr (requires {aw_.await_resume(as_result_tag{});})
0106 return aw_.await_resume(as_result_tag{});
0107 else
0108 {
0109 using type = decltype(aw_.await_resume());
0110 if constexpr (std::is_void_v<type>)
0111 {
0112 using res_t = system::result<type, std::exception_ptr>;
0113 BOOST_TRY
0114 {
0115 aw_.await_resume();
0116 return res_t{system::in_place_value};
0117 }
0118 BOOST_CATCH (...)
0119 {
0120 return res_t{system::in_place_error, std::current_exception()};
0121 }
0122 BOOST_CATCH_END
0123 }
0124 else
0125 {
0126 using res_t = system::result<type, std::exception_ptr>;
0127 BOOST_TRY
0128 {
0129 return res_t{system::in_place_value, aw_.await_resume()};
0130 }
0131 BOOST_CATCH (...)
0132 {
0133 return res_t{system::in_place_error, std::current_exception()};
0134 }
0135 BOOST_CATCH_END
0136 }
0137 }
0138 }
0139 private:
0140 Aw aw_;
0141 };
0142
0143
0144 template<awaitable_type Aw>
0145 as_result_t(Aw &&) -> as_result_t<Aw>;
0146
0147 template<typename Aw_>
0148 requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
0149 as_result_t(Aw_ && aw) -> as_result_t<decltype(std::forward<Aw_>(aw).operator co_await())>;
0150
0151 template<typename Aw_>
0152 requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
0153 as_result_t(Aw_ && aw) -> as_result_t<decltype(operator co_await(std::forward<Aw_>(aw)))>;
0154
0155 template<awaitable_type Aw>
0156 auto as_result(Aw && aw) -> as_result_t<Aw>
0157 {
0158 return as_result_t<Aw>(std::forward<Aw>(aw));
0159 }
0160
0161 template<typename Aw>
0162 requires requires (Aw && aw)
0163 {
0164 {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
0165 }
0166 auto as_result(Aw && aw)
0167 {
0168 struct lazy_tuple
0169 {
0170 Aw aw;
0171 auto operator co_await ()
0172 {
0173 return as_result_t(std::forward<Aw>(aw));
0174 }
0175 };
0176 return lazy_tuple{std::forward<Aw>(aw)};
0177 }
0178
0179 template<typename Aw>
0180 requires requires (Aw && aw)
0181 {
0182 {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
0183 }
0184 auto as_result(Aw && aw)
0185 {
0186 struct lazy_tuple
0187 {
0188 Aw aw;
0189 auto operator co_await ()
0190 {
0191 return as_result_t(std::forward<Aw>(aw));
0192 }
0193 };
0194 return lazy_tuple{std::forward<Aw>(aw)};
0195 }
0196
0197
0198
0199 template<awaitable Aw>
0200 struct as_tuple_t
0201 {
0202 as_tuple_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
0203
0204 template<typename Aw_>
0205 requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
0206 as_tuple_t(Aw_ && aw) : aw_(std::forward<Aw_>(aw).operator co_await()) {}
0207
0208 template<typename Aw_>
0209 requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
0210 as_tuple_t(Aw_ && aw) : aw_(operator co_await(std::forward<Aw_>(aw))) {}
0211
0212
0213 bool await_ready() { return aw_.await_ready();}
0214 template<typename T>
0215 auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
0216
0217 auto await_resume()
0218 {
0219 using type = decltype(aw_.await_resume());
0220 if constexpr (requires {aw_.await_resume(as_tuple_tag{});})
0221 return aw_.await_resume(as_tuple_tag{});
0222 else if constexpr (noexcept(aw_.await_resume()))
0223 {
0224 if constexpr (std::is_void_v<type>)
0225 {
0226 aw_.await_resume();
0227 return std::make_tuple();
0228 }
0229 else
0230 return std::make_tuple(aw_.await_resume());
0231
0232 }
0233 else
0234 {
0235 if constexpr (std::is_void_v<type>)
0236 {
0237 BOOST_TRY
0238 {
0239 aw_.await_resume();
0240 return std::make_tuple(std::exception_ptr());
0241 }
0242 BOOST_CATCH (...)
0243 {
0244 return std::make_tuple(std::current_exception());
0245 }
0246 BOOST_CATCH_END
0247 }
0248 else
0249 {
0250 BOOST_TRY
0251 {
0252 return make_tuple_(std::exception_ptr(), aw_.await_resume());
0253 }
0254 BOOST_CATCH (...)
0255 {
0256 return make_tuple_(std::current_exception(), type());
0257 }
0258 BOOST_CATCH_END
0259 }
0260 }
0261 }
0262 private:
0263 template<typename ... Args>
0264 std::tuple<std::exception_ptr, Args...> make_tuple_(std::exception_ptr ep, std::tuple<Args...> && tup)
0265 {
0266 return std::apply(
0267 [&](auto ... args)
0268 {
0269 return std::make_tuple(std::move(ep), std::move(args)...);
0270 }, std::move(tup));
0271 }
0272
0273 template<typename Arg>
0274 std::tuple<std::exception_ptr, Arg> make_tuple_(std::exception_ptr ep, Arg && arg)
0275 {
0276 return std::make_tuple(std::move(ep), std::move(arg));
0277 }
0278
0279 private:
0280
0281 Aw aw_;
0282 };
0283
0284
0285 template<awaitable_type Aw>
0286 as_tuple_t(Aw &&) -> as_tuple_t<Aw>;
0287
0288 template<typename Aw_>
0289 requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
0290 as_tuple_t(Aw_ && aw) -> as_tuple_t<decltype(std::forward<Aw_>(aw).operator co_await())>;
0291
0292 template<typename Aw_>
0293 requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
0294 as_tuple_t(Aw_ && aw) -> as_tuple_t<decltype(operator co_await(std::forward<Aw_>(aw)))>;
0295
0296
0297 template<awaitable_type Aw>
0298 auto as_tuple(Aw && aw) -> as_tuple_t<Aw>
0299 {
0300 return as_tuple_t<Aw>(std::forward<Aw>(aw));
0301 }
0302
0303 template<typename Aw>
0304 requires requires (Aw && aw)
0305 {
0306 {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
0307 }
0308 auto as_tuple(Aw && aw)
0309 {
0310 struct lazy_tuple
0311 {
0312 Aw aw;
0313 auto operator co_await ()
0314 {
0315 return as_tuple_t(std::forward<Aw>(aw));
0316 }
0317 };
0318 return lazy_tuple{std::forward<Aw>(aw)};
0319 }
0320
0321 template<typename Aw>
0322 requires requires (Aw && aw)
0323 {
0324 {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
0325 }
0326 auto as_tuple(Aw && aw)
0327 {
0328 struct lazy_tuple
0329 {
0330 Aw aw;
0331 auto operator co_await ()
0332 {
0333 return as_tuple_t(std::forward<Aw>(aw));
0334 }
0335 };
0336 return lazy_tuple{std::forward<Aw>(aw)};
0337 }
0338
0339
0340 }
0341
0342 #endif