result.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Copyright (c) 2023 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_COBALT_RESULT_HPP
  6. #define BOOST_COBALT_RESULT_HPP
  7. #include <boost/cobalt/concepts.hpp>
  8. #include <boost/core/no_exceptions_support.hpp>
  9. #include <boost/system/result.hpp>
  10. namespace boost::cobalt
  11. {
  12. namespace detail
  13. {
  14. template<typename T>
  15. concept result_error =
  16. requires (const T & t, const source_location & loc)
  17. {
  18. system::throw_exception_from_error(t, loc);
  19. }
  20. || // ADL
  21. requires (const T & t, const source_location & loc)
  22. {
  23. throw_exception_from_error(t, loc);
  24. }
  25. ;
  26. }
  27. inline constexpr auto interpret_as_result(std::tuple<> &&)
  28. {
  29. return system::result<void>();
  30. }
  31. template<typename Arg>
  32. auto interpret_as_result(std::tuple<Arg> && args)
  33. {
  34. if constexpr (detail::result_error<Arg>)
  35. {
  36. if (std::get<0>(args))
  37. return system::result<void, Arg>(system::in_place_error, std::get<0>(args));
  38. else
  39. return system::result<void, Arg>(system::in_place_value);
  40. }
  41. else
  42. return system::result<Arg>(std::move(std::get<0>(args)));
  43. }
  44. template<typename First, typename ... Args>
  45. requires (!detail::result_error<First> && sizeof...(Args) > 0u)
  46. auto interpret_as_result(std::tuple<First, Args...> && args) -> system::result<std::tuple<First, Args...>>
  47. {
  48. return std::move(args);
  49. }
  50. template<detail::result_error Error, typename ... Args>
  51. requires (sizeof...(Args) > 1u)
  52. auto interpret_as_result(std::tuple<Error, Args...> && args) -> system::result<std::tuple<Args...>, Error>
  53. {
  54. if (std::get<0>(args))
  55. return {system::in_place_error, std::move(std::get<0>(args))};
  56. return {
  57. system::in_place_value,
  58. std::apply([](auto, auto && ... rest) {return std::make_tuple(std::move(rest)...);}, std::move(args))
  59. };
  60. }
  61. template<detail::result_error Error, typename Arg>
  62. auto interpret_as_result(std::tuple<Error, Arg> && args) -> system::result<Arg, Error>
  63. {
  64. if (std::get<0>(args))
  65. return {system::in_place_error, std::get<0>(args)};
  66. return {system::in_place_value, std::get<1>(std::move(args))};
  67. }
  68. struct as_result_tag {};
  69. struct as_tuple_tag {};
  70. template<awaitable_type Aw>
  71. struct as_result_t
  72. {
  73. as_result_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
  74. template<typename Aw_>
  75. requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
  76. as_result_t(Aw_ && aw) : aw_(std::forward<Aw_>(aw).operator co_await()) {}
  77. template<typename Aw_>
  78. requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
  79. as_result_t(Aw_ && aw) : aw_(operator co_await(std::forward<Aw_>(aw))) {}
  80. bool await_ready() { return aw_.await_ready();}
  81. template<typename T>
  82. auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
  83. auto await_resume()
  84. {
  85. if constexpr (requires {aw_.await_resume(as_result_tag{});})
  86. return aw_.await_resume(as_result_tag{});
  87. else
  88. {
  89. using type = decltype(aw_.await_resume());
  90. if constexpr (std::is_void_v<type>)
  91. {
  92. using res_t = system::result<type, std::exception_ptr>;
  93. BOOST_TRY
  94. {
  95. aw_.await_resume();
  96. return res_t{system::in_place_value};
  97. }
  98. BOOST_CATCH (...)
  99. {
  100. return res_t{system::in_place_error, std::current_exception()};
  101. }
  102. BOOST_CATCH_END
  103. }
  104. else
  105. {
  106. using res_t = system::result<type, std::exception_ptr>;
  107. BOOST_TRY
  108. {
  109. return res_t{system::in_place_value, aw_.await_resume()};
  110. }
  111. BOOST_CATCH (...)
  112. {
  113. return res_t{system::in_place_error, std::current_exception()};
  114. }
  115. BOOST_CATCH_END
  116. }
  117. }
  118. }
  119. private:
  120. Aw aw_;
  121. };
  122. template<awaitable_type Aw>
  123. as_result_t(Aw &&) -> as_result_t<Aw>;
  124. template<typename Aw_>
  125. requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
  126. as_result_t(Aw_ && aw) -> as_result_t<decltype(std::forward<Aw_>(aw).operator co_await())>;
  127. template<typename Aw_>
  128. requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
  129. as_result_t(Aw_ && aw) -> as_result_t<decltype(operator co_await(std::forward<Aw_>(aw)))>;
  130. template<awaitable_type Aw>
  131. auto as_result(Aw && aw) -> as_result_t<Aw>
  132. {
  133. return as_result_t<Aw>(std::forward<Aw>(aw));
  134. }
  135. template<typename Aw>
  136. requires requires (Aw && aw)
  137. {
  138. {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
  139. }
  140. auto as_result(Aw && aw)
  141. {
  142. struct lazy_tuple
  143. {
  144. Aw aw;
  145. auto operator co_await ()
  146. {
  147. return as_result_t(std::forward<Aw>(aw));
  148. }
  149. };
  150. return lazy_tuple{std::forward<Aw>(aw)};
  151. }
  152. template<typename Aw>
  153. requires requires (Aw && aw)
  154. {
  155. {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
  156. }
  157. auto as_result(Aw && aw)
  158. {
  159. struct lazy_tuple
  160. {
  161. Aw aw;
  162. auto operator co_await ()
  163. {
  164. return as_result_t(std::forward<Aw>(aw));
  165. }
  166. };
  167. return lazy_tuple{std::forward<Aw>(aw)};
  168. }
  169. template<awaitable Aw>
  170. struct as_tuple_t
  171. {
  172. as_tuple_t(Aw && aw) : aw_(std::forward<Aw>(aw)) {}
  173. template<typename Aw_>
  174. requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
  175. as_tuple_t(Aw_ && aw) : aw_(std::forward<Aw_>(aw).operator co_await()) {}
  176. template<typename Aw_>
  177. requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
  178. as_tuple_t(Aw_ && aw) : aw_(operator co_await(std::forward<Aw_>(aw))) {}
  179. bool await_ready() { return aw_.await_ready();}
  180. template<typename T>
  181. auto await_suspend(std::coroutine_handle<T> h) { return aw_.await_suspend(h);}
  182. auto await_resume()
  183. {
  184. using type = decltype(aw_.await_resume());
  185. if constexpr (requires {aw_.await_resume(as_tuple_tag{});})
  186. return aw_.await_resume(as_tuple_tag{});
  187. else if constexpr (noexcept(aw_.await_resume()))
  188. {
  189. if constexpr (std::is_void_v<type>)
  190. {
  191. aw_.await_resume();
  192. return std::make_tuple();
  193. }
  194. else
  195. return std::make_tuple(aw_.await_resume());
  196. }
  197. else
  198. {
  199. if constexpr (std::is_void_v<type>)
  200. {
  201. BOOST_TRY
  202. {
  203. aw_.await_resume();
  204. return std::make_tuple(std::exception_ptr());
  205. }
  206. BOOST_CATCH (...)
  207. {
  208. return std::make_tuple(std::current_exception());
  209. }
  210. BOOST_CATCH_END
  211. }
  212. else
  213. {
  214. BOOST_TRY
  215. {
  216. return make_tuple_(std::exception_ptr(), aw_.await_resume());
  217. }
  218. BOOST_CATCH (...)
  219. {
  220. return make_tuple_(std::current_exception(), type());
  221. }
  222. BOOST_CATCH_END
  223. }
  224. }
  225. }
  226. private:
  227. template<typename ... Args>
  228. std::tuple<std::exception_ptr, Args...> make_tuple_(std::exception_ptr ep, std::tuple<Args...> && tup)
  229. {
  230. return std::apply(
  231. [&](auto ... args)
  232. {
  233. return std::make_tuple(std::move(ep), std::move(args)...);
  234. }, std::move(tup));
  235. }
  236. template<typename Arg>
  237. std::tuple<std::exception_ptr, Arg> make_tuple_(std::exception_ptr ep, Arg && arg)
  238. {
  239. return std::make_tuple(std::move(ep), std::move(arg));
  240. }
  241. private:
  242. Aw aw_;
  243. };
  244. template<awaitable_type Aw>
  245. as_tuple_t(Aw &&) -> as_tuple_t<Aw>;
  246. template<typename Aw_>
  247. requires requires (Aw_ && aw) {{std::forward<Aw_>(aw).operator co_await()} -> awaitable_type;}
  248. as_tuple_t(Aw_ && aw) -> as_tuple_t<decltype(std::forward<Aw_>(aw).operator co_await())>;
  249. template<typename Aw_>
  250. requires requires (Aw_ && aw) {{operator co_await(std::forward<Aw_>(aw))} -> awaitable_type;}
  251. as_tuple_t(Aw_ && aw) -> as_tuple_t<decltype(operator co_await(std::forward<Aw_>(aw)))>;
  252. template<awaitable_type Aw>
  253. auto as_tuple(Aw && aw) -> as_tuple_t<Aw>
  254. {
  255. return as_tuple_t<Aw>(std::forward<Aw>(aw));
  256. }
  257. template<typename Aw>
  258. requires requires (Aw && aw)
  259. {
  260. {std::forward<Aw>(aw).operator co_await()} -> awaitable_type;
  261. }
  262. auto as_tuple(Aw && aw)
  263. {
  264. struct lazy_tuple
  265. {
  266. Aw aw;
  267. auto operator co_await ()
  268. {
  269. return as_tuple_t(std::forward<Aw>(aw));
  270. }
  271. };
  272. return lazy_tuple{std::forward<Aw>(aw)};
  273. }
  274. template<typename Aw>
  275. requires requires (Aw && aw)
  276. {
  277. {operator co_await(std::forward<Aw>(aw))} -> awaitable_type;
  278. }
  279. auto as_tuple(Aw && aw)
  280. {
  281. struct lazy_tuple
  282. {
  283. Aw aw;
  284. auto operator co_await ()
  285. {
  286. return as_tuple_t(std::forward<Aw>(aw));
  287. }
  288. };
  289. return lazy_tuple{std::forward<Aw>(aw)};
  290. }
  291. }
  292. #endif //BOOST_COBALT_RESULT_HPP