coro.hpp 28 KB

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