coro.hpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. //
  2. // experimental/impl/coro.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2021-2023 Klemens D. Morgenstern
  6. // (klemens dot morgenstern at gmx dot net)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef ASIO_EXPERIMENTAL_IMPL_CORO_HPP
  12. #define ASIO_EXPERIMENTAL_IMPL_CORO_HPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include "asio/detail/config.hpp"
  17. #include "asio/append.hpp"
  18. #include "asio/associated_cancellation_slot.hpp"
  19. #include "asio/bind_allocator.hpp"
  20. #include "asio/deferred.hpp"
  21. #include "asio/experimental/detail/coro_completion_handler.hpp"
  22. #include "asio/detail/push_options.hpp"
  23. namespace asio {
  24. namespace experimental {
  25. template <typename Yield, typename Return,
  26. typename Executor, typename Allocator>
  27. struct coro;
  28. namespace detail {
  29. struct coro_cancellation_source
  30. {
  31. cancellation_slot slot;
  32. cancellation_state state;
  33. bool throw_if_cancelled_ = true;
  34. void reset_cancellation_state()
  35. {
  36. state = cancellation_state(slot);
  37. }
  38. template <typename Filter>
  39. void reset_cancellation_state(Filter&& filter)
  40. {
  41. state = cancellation_state(slot, static_cast<Filter&&>(filter));
  42. }
  43. template <typename InFilter, typename OutFilter>
  44. void reset_cancellation_state(InFilter&& in_filter,
  45. OutFilter&& out_filter)
  46. {
  47. state = cancellation_state(slot,
  48. static_cast<InFilter&&>(in_filter),
  49. static_cast<OutFilter&&>(out_filter));
  50. }
  51. bool throw_if_cancelled() const
  52. {
  53. return throw_if_cancelled_;
  54. }
  55. void throw_if_cancelled(bool value)
  56. {
  57. throw_if_cancelled_ = value;
  58. }
  59. };
  60. template <typename Signature, typename Return,
  61. typename Executor, typename Allocator>
  62. struct coro_promise;
  63. template <typename T>
  64. struct is_noexcept : std::false_type
  65. {
  66. };
  67. template <typename Return, typename... Args>
  68. struct is_noexcept<Return(Args...)> : std::false_type
  69. {
  70. };
  71. template <typename Return, typename... Args>
  72. struct is_noexcept<Return(Args...) noexcept> : std::true_type
  73. {
  74. };
  75. template <typename T>
  76. constexpr bool is_noexcept_v = is_noexcept<T>::value;
  77. template <typename T>
  78. struct coro_error;
  79. template <>
  80. struct coro_error<asio::error_code>
  81. {
  82. static asio::error_code invalid()
  83. {
  84. return asio::error::fault;
  85. }
  86. static asio::error_code cancelled()
  87. {
  88. return asio::error::operation_aborted;
  89. }
  90. static asio::error_code interrupted()
  91. {
  92. return asio::error::interrupted;
  93. }
  94. static asio::error_code done()
  95. {
  96. return asio::error::broken_pipe;
  97. }
  98. };
  99. template <>
  100. struct coro_error<std::exception_ptr>
  101. {
  102. static std::exception_ptr invalid()
  103. {
  104. return std::make_exception_ptr(
  105. asio::system_error(
  106. coro_error<asio::error_code>::invalid()));
  107. }
  108. static std::exception_ptr cancelled()
  109. {
  110. return std::make_exception_ptr(
  111. asio::system_error(
  112. coro_error<asio::error_code>::cancelled()));
  113. }
  114. static std::exception_ptr interrupted()
  115. {
  116. return std::make_exception_ptr(
  117. asio::system_error(
  118. coro_error<asio::error_code>::interrupted()));
  119. }
  120. static std::exception_ptr done()
  121. {
  122. return std::make_exception_ptr(
  123. asio::system_error(
  124. coro_error<asio::error_code>::done()));
  125. }
  126. };
  127. template <typename T, typename Coroutine >
  128. struct coro_with_arg
  129. {
  130. using coro_t = Coroutine;
  131. T value;
  132. coro_t& coro;
  133. struct awaitable_t
  134. {
  135. T value;
  136. coro_t& coro;
  137. constexpr static bool await_ready() { return false; }
  138. template <typename Y, typename R, typename E, typename A>
  139. auto await_suspend(coroutine_handle<coro_promise<Y, R, E, A>> h)
  140. -> coroutine_handle<>
  141. {
  142. auto& hp = h.promise();
  143. if constexpr (!coro_promise<Y, R, E, A>::is_noexcept)
  144. {
  145. if ((hp.cancel->state.cancelled() != cancellation_type::none)
  146. && hp.cancel->throw_if_cancelled_)
  147. {
  148. asio::detail::throw_error(
  149. asio::error::operation_aborted, "coro-cancelled");
  150. }
  151. }
  152. if (hp.get_executor() == coro.get_executor())
  153. {
  154. coro.coro_->awaited_from = h;
  155. coro.coro_->reset_error();
  156. coro.coro_->input_ = std::move(value);
  157. coro.coro_->cancel = hp.cancel;
  158. return coro.coro_->get_handle();
  159. }
  160. else
  161. {
  162. coro.coro_->awaited_from =
  163. dispatch_coroutine(
  164. asio::prefer(hp.get_executor(),
  165. execution::outstanding_work.tracked),
  166. [h]() mutable { h.resume(); }).handle;
  167. coro.coro_->reset_error();
  168. coro.coro_->input_ = std::move(value);
  169. struct cancel_handler
  170. {
  171. using src = std::pair<cancellation_signal,
  172. detail::coro_cancellation_source>;
  173. std::shared_ptr<src> st = std::make_shared<src>();
  174. cancel_handler(E e, coro_t& coro) : e(e), coro_(coro.coro_)
  175. {
  176. st->second.state =
  177. cancellation_state(st->second.slot = st->first.slot());
  178. }
  179. E e;
  180. typename coro_t::promise_type* coro_;
  181. void operator()(cancellation_type ct)
  182. {
  183. asio::dispatch(e, [ct, st = st]() mutable
  184. {
  185. auto & [sig, state] = *st;
  186. sig.emit(ct);
  187. });
  188. }
  189. };
  190. if (hp.cancel->state.slot().is_connected())
  191. {
  192. hp.cancel->state.slot().template emplace<cancel_handler>(
  193. coro.get_executor(), coro);
  194. }
  195. auto hh = detail::coroutine_handle<
  196. typename coro_t::promise_type>::from_promise(*coro.coro_);
  197. return dispatch_coroutine(
  198. coro.coro_->get_executor(), [hh]() mutable { hh.resume(); }).handle;
  199. }
  200. }
  201. auto await_resume() -> typename coro_t::result_type
  202. {
  203. coro.coro_->cancel = nullptr;
  204. coro.coro_->rethrow_if();
  205. return std::move(coro.coro_->result_);
  206. }
  207. };
  208. template <typename CompletionToken>
  209. auto async_resume(CompletionToken&& token) &&
  210. {
  211. return coro.async_resume(std::move(value),
  212. std::forward<CompletionToken>(token));
  213. }
  214. auto operator co_await() &&
  215. {
  216. return awaitable_t{std::move(value), coro};
  217. }
  218. };
  219. template <bool IsNoexcept>
  220. struct coro_promise_error;
  221. template <>
  222. struct coro_promise_error<false>
  223. {
  224. std::exception_ptr error_;
  225. void reset_error()
  226. {
  227. error_ = std::exception_ptr{};
  228. }
  229. void unhandled_exception()
  230. {
  231. error_ = std::current_exception();
  232. }
  233. void rethrow_if()
  234. {
  235. if (error_)
  236. std::rethrow_exception(error_);
  237. }
  238. };
  239. #if defined(__GNUC__)
  240. # pragma GCC diagnostic push
  241. # if defined(__clang__)
  242. # pragma GCC diagnostic ignored "-Wexceptions"
  243. # else
  244. # pragma GCC diagnostic ignored "-Wterminate"
  245. # endif
  246. #elif defined(_MSC_VER)
  247. # pragma warning(push)
  248. # pragma warning (disable:4297)
  249. #endif
  250. template <>
  251. struct coro_promise_error<true>
  252. {
  253. void reset_error()
  254. {
  255. }
  256. void unhandled_exception() noexcept
  257. {
  258. throw;
  259. }
  260. void rethrow_if()
  261. {
  262. }
  263. };
  264. #if defined(__GNUC__)
  265. # pragma GCC diagnostic pop
  266. #elif defined(_MSC_VER)
  267. # pragma warning(pop)
  268. #endif
  269. template <typename T = void>
  270. struct yield_input
  271. {
  272. T& value;
  273. coroutine_handle<> awaited_from{noop_coroutine()};
  274. bool await_ready() const noexcept
  275. {
  276. return false;
  277. }
  278. template <typename U>
  279. coroutine_handle<> await_suspend(coroutine_handle<U>) noexcept
  280. {
  281. return std::exchange(awaited_from, noop_coroutine());
  282. }
  283. T await_resume() const noexcept
  284. {
  285. return std::move(value);
  286. }
  287. };
  288. template <>
  289. struct yield_input<void>
  290. {
  291. coroutine_handle<> awaited_from{noop_coroutine()};
  292. bool await_ready() const noexcept
  293. {
  294. return false;
  295. }
  296. auto await_suspend(coroutine_handle<>) noexcept
  297. {
  298. return std::exchange(awaited_from, noop_coroutine());
  299. }
  300. constexpr void await_resume() const noexcept
  301. {
  302. }
  303. };
  304. struct coro_awaited_from
  305. {
  306. coroutine_handle<> awaited_from{noop_coroutine()};
  307. auto final_suspend() noexcept
  308. {
  309. struct suspendor
  310. {
  311. coroutine_handle<> awaited_from;
  312. constexpr static bool await_ready() noexcept
  313. {
  314. return false;
  315. }
  316. auto await_suspend(coroutine_handle<>) noexcept
  317. {
  318. return std::exchange(awaited_from, noop_coroutine());
  319. }
  320. constexpr static void await_resume() noexcept
  321. {
  322. }
  323. };
  324. return suspendor{std::exchange(awaited_from, noop_coroutine())};
  325. }
  326. ~coro_awaited_from()
  327. {
  328. awaited_from.resume();
  329. }//must be on the right executor
  330. };
  331. template <typename Yield, typename Input, typename Return>
  332. struct coro_promise_exchange : coro_awaited_from
  333. {
  334. using result_type = coro_result_t<Yield, Return>;
  335. result_type result_;
  336. Input input_;
  337. auto yield_value(Yield&& y)
  338. {
  339. result_ = std::move(y);
  340. return yield_input<Input>{std::move(input_),
  341. std::exchange(awaited_from, noop_coroutine())};
  342. }
  343. auto yield_value(const Yield& y)
  344. {
  345. result_ = y;
  346. return yield_input<Input>{std::move(input_),
  347. std::exchange(awaited_from, noop_coroutine())};
  348. }
  349. void return_value(const Return& r)
  350. {
  351. result_ = r;
  352. }
  353. void return_value(Return&& r)
  354. {
  355. result_ = std::move(r);
  356. }
  357. };
  358. template <typename YieldReturn>
  359. struct coro_promise_exchange<YieldReturn, void, YieldReturn> : coro_awaited_from
  360. {
  361. using result_type = coro_result_t<YieldReturn, YieldReturn>;
  362. result_type result_;
  363. auto yield_value(const YieldReturn& y)
  364. {
  365. result_ = y;
  366. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  367. }
  368. auto yield_value(YieldReturn&& y)
  369. {
  370. result_ = std::move(y);
  371. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  372. }
  373. void return_value(const YieldReturn& r)
  374. {
  375. result_ = r;
  376. }
  377. void return_value(YieldReturn&& r)
  378. {
  379. result_ = std::move(r);
  380. }
  381. };
  382. template <typename Yield, typename Return>
  383. struct coro_promise_exchange<Yield, void, Return> : coro_awaited_from
  384. {
  385. using result_type = coro_result_t<Yield, Return>;
  386. result_type result_;
  387. auto yield_value(const Yield& y)
  388. {
  389. result_.template emplace<0>(y);
  390. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  391. }
  392. auto yield_value(Yield&& y)
  393. {
  394. result_.template emplace<0>(std::move(y));
  395. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  396. }
  397. void return_value(const Return& r)
  398. {
  399. result_.template emplace<1>(r);
  400. }
  401. void return_value(Return&& r)
  402. {
  403. result_.template emplace<1>(std::move(r));
  404. }
  405. };
  406. template <typename Yield, typename Input>
  407. struct coro_promise_exchange<Yield, Input, void> : coro_awaited_from
  408. {
  409. using result_type = coro_result_t<Yield, void>;
  410. result_type result_;
  411. Input input_;
  412. auto yield_value(Yield&& y)
  413. {
  414. result_ = std::move(y);
  415. return yield_input<Input>{input_,
  416. std::exchange(awaited_from, noop_coroutine())};
  417. }
  418. auto yield_value(const Yield& y)
  419. {
  420. result_ = y;
  421. return yield_input<Input>{input_,
  422. std::exchange(awaited_from, noop_coroutine())};
  423. }
  424. void return_void()
  425. {
  426. result_.reset();
  427. }
  428. };
  429. template <typename Return>
  430. struct coro_promise_exchange<void, void, Return> : coro_awaited_from
  431. {
  432. using result_type = coro_result_t<void, Return>;
  433. result_type result_;
  434. void yield_value();
  435. void return_value(const Return& r)
  436. {
  437. result_ = r;
  438. }
  439. void return_value(Return&& r)
  440. {
  441. result_ = std::move(r);
  442. }
  443. };
  444. template <>
  445. struct coro_promise_exchange<void, void, void> : coro_awaited_from
  446. {
  447. void return_void() {}
  448. void yield_value();
  449. };
  450. template <typename Yield>
  451. struct coro_promise_exchange<Yield, void, void> : coro_awaited_from
  452. {
  453. using result_type = coro_result_t<Yield, void>;
  454. result_type result_;
  455. auto yield_value(const Yield& y)
  456. {
  457. result_ = y;
  458. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  459. }
  460. auto yield_value(Yield&& y)
  461. {
  462. result_ = std::move(y);
  463. return yield_input<void>{std::exchange(awaited_from, noop_coroutine())};
  464. }
  465. void return_void()
  466. {
  467. result_.reset();
  468. }
  469. };
  470. template <typename Yield, typename Return,
  471. typename Executor, typename Allocator>
  472. struct coro_promise final :
  473. coro_promise_allocator<Allocator>,
  474. coro_promise_error<coro_traits<Yield, Return, Executor>::is_noexcept>,
  475. coro_promise_exchange<
  476. typename coro_traits<Yield, Return, Executor>::yield_type,
  477. typename coro_traits<Yield, Return, Executor>::input_type,
  478. typename coro_traits<Yield, Return, Executor>::return_type>
  479. {
  480. using coro_type = coro<Yield, Return, Executor, Allocator>;
  481. auto handle()
  482. {
  483. return coroutine_handle<coro_promise>::from_promise(this);
  484. }
  485. using executor_type = Executor;
  486. executor_type executor_;
  487. std::optional<coro_cancellation_source> cancel_source;
  488. coro_cancellation_source * cancel;
  489. using cancellation_slot_type = asio::cancellation_slot;
  490. cancellation_slot_type get_cancellation_slot() const noexcept
  491. {
  492. return cancel ? cancel->slot : cancellation_slot_type{};
  493. }
  494. using allocator_type =
  495. typename std::allocator_traits<associated_allocator_t<Executor>>::
  496. template rebind_alloc<std::byte>;
  497. using traits = coro_traits<Yield, Return, Executor>;
  498. using input_type = typename traits::input_type;
  499. using yield_type = typename traits::yield_type;
  500. using return_type = typename traits::return_type;
  501. using error_type = typename traits::error_type;
  502. using result_type = typename traits::result_type;
  503. constexpr static bool is_noexcept = traits::is_noexcept;
  504. auto get_executor() const -> Executor
  505. {
  506. return executor_;
  507. }
  508. auto get_handle()
  509. {
  510. return coroutine_handle<coro_promise>::from_promise(*this);
  511. }
  512. template <typename... Args>
  513. coro_promise(Executor executor, Args&&... args) noexcept
  514. : coro_promise_allocator<Allocator>(
  515. executor, std::forward<Args>(args)...),
  516. executor_(std::move(executor))
  517. {
  518. }
  519. template <typename First, typename... Args>
  520. coro_promise(First&& f, Executor executor, Args&&... args) noexcept
  521. : coro_promise_allocator<Allocator>(
  522. f, executor, std::forward<Args>(args)...),
  523. executor_(std::move(executor))
  524. {
  525. }
  526. template <typename First, detail::execution_context Context, typename... Args>
  527. coro_promise(First&& f, Context&& ctx, Args&&... args) noexcept
  528. : coro_promise_allocator<Allocator>(
  529. f, ctx, std::forward<Args>(args)...),
  530. executor_(ctx.get_executor())
  531. {
  532. }
  533. template <detail::execution_context Context, typename... Args>
  534. coro_promise(Context&& ctx, Args&&... args) noexcept
  535. : coro_promise_allocator<Allocator>(
  536. ctx, std::forward<Args>(args)...),
  537. executor_(ctx.get_executor())
  538. {
  539. }
  540. auto get_return_object()
  541. {
  542. return coro<Yield, Return, Executor, Allocator>{this};
  543. }
  544. auto initial_suspend() noexcept
  545. {
  546. return suspend_always{};
  547. }
  548. using coro_promise_exchange<
  549. typename coro_traits<Yield, Return, Executor>::yield_type,
  550. typename coro_traits<Yield, Return, Executor>::input_type,
  551. typename coro_traits<Yield, Return, Executor>::return_type>::yield_value;
  552. auto await_transform(this_coro::executor_t) const
  553. {
  554. struct exec_helper
  555. {
  556. const executor_type& value;
  557. constexpr static bool await_ready() noexcept
  558. {
  559. return true;
  560. }
  561. constexpr static void await_suspend(coroutine_handle<>) noexcept
  562. {
  563. }
  564. executor_type await_resume() const noexcept
  565. {
  566. return value;
  567. }
  568. };
  569. return exec_helper{executor_};
  570. }
  571. auto await_transform(this_coro::cancellation_state_t) const
  572. {
  573. struct exec_helper
  574. {
  575. const asio::cancellation_state& value;
  576. constexpr static bool await_ready() noexcept
  577. {
  578. return true;
  579. }
  580. constexpr static void await_suspend(coroutine_handle<>) noexcept
  581. {
  582. }
  583. asio::cancellation_state await_resume() const noexcept
  584. {
  585. return value;
  586. }
  587. };
  588. assert(cancel);
  589. return exec_helper{cancel->state};
  590. }
  591. // This await transformation resets the associated cancellation state.
  592. auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept
  593. {
  594. struct result
  595. {
  596. detail::coro_cancellation_source * src_;
  597. bool await_ready() const noexcept
  598. {
  599. return true;
  600. }
  601. void await_suspend(coroutine_handle<void>) noexcept
  602. {
  603. }
  604. auto await_resume() const
  605. {
  606. return src_->reset_cancellation_state();
  607. }
  608. };
  609. return result{cancel};
  610. }
  611. // This await transformation resets the associated cancellation state.
  612. template <typename Filter>
  613. auto await_transform(
  614. this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept
  615. {
  616. struct result
  617. {
  618. detail::coro_cancellation_source* src_;
  619. Filter filter_;
  620. bool await_ready() const noexcept
  621. {
  622. return true;
  623. }
  624. void await_suspend(coroutine_handle<void>) noexcept
  625. {
  626. }
  627. auto await_resume()
  628. {
  629. return src_->reset_cancellation_state(
  630. static_cast<Filter&&>(filter_));
  631. }
  632. };
  633. return result{cancel, static_cast<Filter&&>(reset.filter)};
  634. }
  635. // This await transformation resets the associated cancellation state.
  636. template <typename InFilter, typename OutFilter>
  637. auto await_transform(
  638. this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset)
  639. noexcept
  640. {
  641. struct result
  642. {
  643. detail::coro_cancellation_source* src_;
  644. InFilter in_filter_;
  645. OutFilter out_filter_;
  646. bool await_ready() const noexcept
  647. {
  648. return true;
  649. }
  650. void await_suspend(coroutine_handle<void>) noexcept
  651. {
  652. }
  653. auto await_resume()
  654. {
  655. return src_->reset_cancellation_state(
  656. static_cast<InFilter&&>(in_filter_),
  657. static_cast<OutFilter&&>(out_filter_));
  658. }
  659. };
  660. return result{cancel,
  661. static_cast<InFilter&&>(reset.in_filter),
  662. static_cast<OutFilter&&>(reset.out_filter)};
  663. }
  664. // This await transformation determines whether cancellation is propagated as
  665. // an exception.
  666. auto await_transform(this_coro::throw_if_cancelled_0_t) noexcept
  667. requires (!is_noexcept)
  668. {
  669. struct result
  670. {
  671. detail::coro_cancellation_source* src_;
  672. bool await_ready() const noexcept
  673. {
  674. return true;
  675. }
  676. void await_suspend(coroutine_handle<void>) noexcept
  677. {
  678. }
  679. auto await_resume()
  680. {
  681. return src_->throw_if_cancelled();
  682. }
  683. };
  684. return result{cancel};
  685. }
  686. // This await transformation sets whether cancellation is propagated as an
  687. // exception.
  688. auto await_transform(
  689. this_coro::throw_if_cancelled_1_t throw_if_cancelled) noexcept
  690. requires (!is_noexcept)
  691. {
  692. struct result
  693. {
  694. detail::coro_cancellation_source* src_;
  695. bool value_;
  696. bool await_ready() const noexcept
  697. {
  698. return true;
  699. }
  700. void await_suspend(coroutine_handle<void>) noexcept
  701. {
  702. }
  703. auto await_resume()
  704. {
  705. src_->throw_if_cancelled(value_);
  706. }
  707. };
  708. return result{cancel, throw_if_cancelled.value};
  709. }
  710. template <typename Yield_, typename Return_,
  711. typename Executor_, typename Allocator_>
  712. auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>& kr)
  713. -> decltype(auto)
  714. {
  715. return kr;
  716. }
  717. template <typename Yield_, typename Return_,
  718. typename Executor_, typename Allocator_>
  719. auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>&& kr)
  720. {
  721. return std::move(kr);
  722. }
  723. template <typename T_, typename Coroutine >
  724. auto await_transform(coro_with_arg<T_, Coroutine>&& kr) -> decltype(auto)
  725. {
  726. return std::move(kr);
  727. }
  728. template <typename T_>
  729. requires requires(T_ t) {{ t.async_wait(deferred) }; }
  730. auto await_transform(T_& t) -> decltype(auto)
  731. {
  732. return await_transform(t.async_wait(deferred));
  733. }
  734. template <typename Op>
  735. auto await_transform(Op&& op,
  736. constraint_t<is_async_operation<Op>::value> = 0)
  737. {
  738. if ((cancel->state.cancelled() != cancellation_type::none)
  739. && cancel->throw_if_cancelled_)
  740. {
  741. asio::detail::throw_error(
  742. asio::error::operation_aborted, "coro-cancelled");
  743. }
  744. using signature = completion_signature_of_t<Op>;
  745. using result_type = detail::coro_completion_handler_type_t<signature>;
  746. using handler_type =
  747. typename detail::coro_completion_handler_type<signature>::template
  748. completion_handler<coro_promise>;
  749. struct aw_t
  750. {
  751. Op op;
  752. std::optional<result_type> result;
  753. constexpr static bool await_ready()
  754. {
  755. return false;
  756. }
  757. void await_suspend(coroutine_handle<coro_promise> h)
  758. {
  759. std::move(op)(handler_type{h, result});
  760. }
  761. auto await_resume()
  762. {
  763. if constexpr (is_noexcept)
  764. {
  765. if constexpr (std::tuple_size_v<result_type> == 0u)
  766. return;
  767. else if constexpr (std::tuple_size_v<result_type> == 1u)
  768. return std::get<0>(std::move(result).value());
  769. else
  770. return std::move(result).value();
  771. }
  772. else
  773. return detail::coro_interpret_result(std::move(result).value());
  774. }
  775. };
  776. return aw_t{std::move(op), {}};
  777. }
  778. };
  779. } // namespace detail
  780. template <typename Yield, typename Return,
  781. typename Executor, typename Allocator>
  782. struct coro<Yield, Return, Executor, Allocator>::awaitable_t
  783. {
  784. coro& coro_;
  785. constexpr static bool await_ready() { return false; }
  786. template <typename Y, typename R, typename E, typename A>
  787. auto await_suspend(
  788. detail::coroutine_handle<detail::coro_promise<Y, R, E, A>> h)
  789. -> detail::coroutine_handle<>
  790. {
  791. auto& hp = h.promise();
  792. if constexpr (!detail::coro_promise<Y, R, E, A>::is_noexcept)
  793. {
  794. if ((hp.cancel->state.cancelled() != cancellation_type::none)
  795. && hp.cancel->throw_if_cancelled_)
  796. {
  797. asio::detail::throw_error(
  798. asio::error::operation_aborted, "coro-cancelled");
  799. }
  800. }
  801. if (hp.get_executor() == coro_.get_executor())
  802. {
  803. coro_.coro_->awaited_from = h;
  804. coro_.coro_->cancel = hp.cancel;
  805. coro_.coro_->reset_error();
  806. return coro_.coro_->get_handle();
  807. }
  808. else
  809. {
  810. coro_.coro_->awaited_from = detail::dispatch_coroutine(
  811. asio::prefer(hp.get_executor(),
  812. execution::outstanding_work.tracked),
  813. [h]() mutable
  814. {
  815. h.resume();
  816. }).handle;
  817. coro_.coro_->reset_error();
  818. struct cancel_handler
  819. {
  820. std::shared_ptr<std::pair<cancellation_signal,
  821. detail::coro_cancellation_source>> st = std::make_shared<
  822. std::pair<cancellation_signal, detail::coro_cancellation_source>>();
  823. cancel_handler(E e, coro& coro) : e(e), coro_(coro.coro_)
  824. {
  825. st->second.state = cancellation_state(
  826. st->second.slot = st->first.slot());
  827. }
  828. E e;
  829. typename coro::promise_type* coro_;
  830. void operator()(cancellation_type ct)
  831. {
  832. asio::dispatch(e,
  833. [ct, st = st]() mutable
  834. {
  835. auto & [sig, state] = *st;
  836. sig.emit(ct);
  837. });
  838. }
  839. };
  840. if (hp.cancel->state.slot().is_connected())
  841. {
  842. hp.cancel->state.slot().template emplace<cancel_handler>(
  843. coro_.get_executor(), coro_);
  844. }
  845. auto hh = detail::coroutine_handle<
  846. detail::coro_promise<Yield, Return, Executor, Allocator>>::from_promise(
  847. *coro_.coro_);
  848. return detail::dispatch_coroutine(
  849. coro_.coro_->get_executor(),
  850. [hh]() mutable { hh.resume(); }).handle;
  851. }
  852. }
  853. auto await_resume() -> result_type
  854. {
  855. coro_.coro_->cancel = nullptr;
  856. coro_.coro_->rethrow_if();
  857. if constexpr (!std::is_void_v<result_type>)
  858. return std::move(coro_.coro_->result_);
  859. }
  860. };
  861. template <typename Yield, typename Return,
  862. typename Executor, typename Allocator>
  863. struct coro<Yield, Return, Executor, Allocator>::initiate_async_resume
  864. {
  865. typedef Executor executor_type;
  866. typedef Allocator allocator_type;
  867. typedef asio::cancellation_slot cancellation_slot_type;
  868. explicit initiate_async_resume(coro* self)
  869. : coro_(self->coro_)
  870. {
  871. }
  872. executor_type get_executor() const noexcept
  873. {
  874. return coro_->get_executor();
  875. }
  876. allocator_type get_allocator() const noexcept
  877. {
  878. return coro_->get_allocator();
  879. }
  880. template <typename E, typename WaitHandler>
  881. auto handle(E exec, WaitHandler&& handler,
  882. std::true_type /* error is noexcept */,
  883. std::true_type /* result is void */) //noexcept
  884. {
  885. return [this, the_coro = coro_,
  886. h = std::forward<WaitHandler>(handler),
  887. exec = std::move(exec)]() mutable
  888. {
  889. assert(the_coro);
  890. auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
  891. assert(ch && !ch.done());
  892. the_coro->awaited_from = post_coroutine(std::move(exec), std::move(h));
  893. the_coro->reset_error();
  894. ch.resume();
  895. };
  896. }
  897. template <typename E, typename WaitHandler>
  898. requires (!std::is_void_v<result_type>)
  899. auto handle(E exec, WaitHandler&& handler,
  900. std::true_type /* error is noexcept */,
  901. std::false_type /* result is void */) //noexcept
  902. {
  903. return [the_coro = coro_,
  904. h = std::forward<WaitHandler>(handler),
  905. exec = std::move(exec)]() mutable
  906. {
  907. assert(the_coro);
  908. auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
  909. assert(ch && !ch.done());
  910. the_coro->awaited_from = detail::post_coroutine(
  911. exec, std::move(h), the_coro->result_).handle;
  912. the_coro->reset_error();
  913. ch.resume();
  914. };
  915. }
  916. template <typename E, typename WaitHandler>
  917. auto handle(E exec, WaitHandler&& handler,
  918. std::false_type /* error is noexcept */,
  919. std::true_type /* result is void */)
  920. {
  921. return [the_coro = coro_,
  922. h = std::forward<WaitHandler>(handler),
  923. exec = std::move(exec)]() mutable
  924. {
  925. if (!the_coro)
  926. return asio::post(exec,
  927. asio::append(std::move(h),
  928. detail::coro_error<error_type>::invalid()));
  929. auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro);
  930. if (!ch)
  931. return asio::post(exec,
  932. asio::append(std::move(h),
  933. detail::coro_error<error_type>::invalid()));
  934. else if (ch.done())
  935. return asio::post(exec,
  936. asio::append(std::move(h),
  937. detail::coro_error<error_type>::done()));
  938. else
  939. {
  940. the_coro->awaited_from = detail::post_coroutine(
  941. exec, std::move(h), the_coro->error_).handle;
  942. the_coro->reset_error();
  943. ch.resume();
  944. }
  945. };
  946. }
  947. template <typename E, typename WaitHandler>
  948. auto handle(E exec, WaitHandler&& handler,
  949. std::false_type /* error is noexcept */,
  950. std::false_type /* result is void */)
  951. {
  952. return [the_coro = coro_,
  953. h = std::forward<WaitHandler>(handler),
  954. exec = std::move(exec)]() mutable
  955. {
  956. if (!the_coro)
  957. return asio::post(exec,
  958. asio::append(std::move(h),
  959. detail::coro_error<error_type>::invalid(), result_type{}));
  960. auto ch =
  961. detail::coroutine_handle<promise_type>::from_promise(*the_coro);
  962. if (!ch)
  963. return asio::post(exec,
  964. asio::append(std::move(h),
  965. detail::coro_error<error_type>::invalid(), result_type{}));
  966. else if (ch.done())
  967. return asio::post(exec,
  968. asio::append(std::move(h),
  969. detail::coro_error<error_type>::done(), result_type{}));
  970. else
  971. {
  972. the_coro->awaited_from = detail::post_coroutine(
  973. exec, std::move(h), the_coro->error_, the_coro->result_).handle;
  974. the_coro->reset_error();
  975. ch.resume();
  976. }
  977. };
  978. }
  979. template <typename WaitHandler>
  980. void operator()(WaitHandler&& handler)
  981. {
  982. const auto exec = asio::prefer(
  983. get_associated_executor(handler, get_executor()),
  984. execution::outstanding_work.tracked);
  985. coro_->cancel = &coro_->cancel_source.emplace();
  986. coro_->cancel->state = cancellation_state(
  987. coro_->cancel->slot = get_associated_cancellation_slot(handler));
  988. asio::dispatch(get_executor(),
  989. handle(exec, std::forward<WaitHandler>(handler),
  990. std::integral_constant<bool, is_noexcept>{},
  991. std::is_void<result_type>{}));
  992. }
  993. template <typename WaitHandler, typename Input>
  994. void operator()(WaitHandler&& handler, Input&& input)
  995. {
  996. const auto exec = asio::prefer(
  997. get_associated_executor(handler, get_executor()),
  998. execution::outstanding_work.tracked);
  999. coro_->cancel = &coro_->cancel_source.emplace();
  1000. coro_->cancel->state = cancellation_state(
  1001. coro_->cancel->slot = get_associated_cancellation_slot(handler));
  1002. asio::dispatch(get_executor(),
  1003. [h = handle(exec, std::forward<WaitHandler>(handler),
  1004. std::integral_constant<bool, is_noexcept>{},
  1005. std::is_void<result_type>{}),
  1006. in = std::forward<Input>(input), the_coro = coro_]() mutable
  1007. {
  1008. the_coro->input_ = std::move(in);
  1009. std::move(h)();
  1010. });
  1011. }
  1012. private:
  1013. typename coro::promise_type* coro_;
  1014. };
  1015. } // namespace experimental
  1016. } // namespace asio
  1017. #include "asio/detail/pop_options.hpp"
  1018. #endif // ASIO_EXPERIMENTAL_IMPL_CORO_HPP