promise.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. //
  2. // experimental/promise.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_PROMISE_HPP
  12. #define ASIO_EXPERIMENTAL_PROMISE_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/type_traits.hpp"
  18. #include "asio/any_io_executor.hpp"
  19. #include "asio/associated_cancellation_slot.hpp"
  20. #include "asio/associated_executor.hpp"
  21. #include "asio/bind_executor.hpp"
  22. #include "asio/cancellation_signal.hpp"
  23. #include "asio/dispatch.hpp"
  24. #include "asio/experimental/impl/promise.hpp"
  25. #include "asio/post.hpp"
  26. #include <algorithm>
  27. #include "asio/detail/push_options.hpp"
  28. namespace asio {
  29. namespace experimental {
  30. template <typename T>
  31. struct is_promise : std::false_type {};
  32. template <typename ... Ts>
  33. struct is_promise<promise<Ts...>> : std::true_type {};
  34. template <typename T>
  35. constexpr bool is_promise_v = is_promise<T>::value;
  36. template <typename ... Ts>
  37. struct promise_value_type
  38. {
  39. using type = std::tuple<Ts...>;
  40. };
  41. template <typename T>
  42. struct promise_value_type<T>
  43. {
  44. using type = T;
  45. };
  46. template <>
  47. struct promise_value_type<>
  48. {
  49. using type = std::tuple<>;
  50. };
  51. #if defined(GENERATING_DOCUMENTATION)
  52. /// A disposable handle for an eager operation.
  53. /**
  54. * @tparam Signature The signature of the operation.
  55. *
  56. * @tparam Executor The executor to be used by the promise (taken from the
  57. * operation).
  58. *
  59. * @tparam Allocator The allocator used for the promise. Can be set through
  60. * use_allocator.
  61. *
  62. * A promise can be used to initiate an asynchronous option that can be
  63. * completed later. If the promise gets destroyed before completion, the
  64. * operation gets a cancel signal and the result is ignored.
  65. *
  66. * A promise fulfills the requirements of async_operation.
  67. *
  68. * @par Examples
  69. * Reading and writing from one coroutine.
  70. * @code
  71. * awaitable<void> read_write_some(asio::ip::tcp::socket & sock,
  72. * asio::mutable_buffer read_buf, asio::const_buffer to_write)
  73. * {
  74. * auto p = asio::async_read(read_buf, asio::use_awaitable);
  75. * co_await asio::async_write_some(to_write, asio::deferred);
  76. * co_await p;
  77. * }
  78. * @endcode
  79. */
  80. template<typename Signature = void(),
  81. typename Executor = asio::any_io_executor,
  82. typename Allocator = std::allocator<void>>
  83. struct promise
  84. #else
  85. template <typename ... Ts, typename Executor, typename Allocator>
  86. struct promise<void(Ts...), Executor, Allocator>
  87. #endif // defined(GENERATING_DOCUMENTATION)
  88. {
  89. /// The value that's returned by the promise.
  90. using value_type = typename promise_value_type<Ts...>::type;
  91. /// Cancel the promise. Usually done through the destructor.
  92. void cancel(cancellation_type level = cancellation_type::all)
  93. {
  94. if (impl_ && !impl_->done)
  95. {
  96. asio::dispatch(impl_->executor,
  97. [level, impl = impl_]{ impl->cancel.emit(level); });
  98. }
  99. }
  100. /// Check if the promise is completed already.
  101. bool completed() const noexcept
  102. {
  103. return impl_ && impl_->done;
  104. }
  105. /// Wait for the promise to become ready.
  106. template <ASIO_COMPLETION_TOKEN_FOR(void(Ts...)) CompletionToken>
  107. inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(Ts...))
  108. operator()(CompletionToken&& token)
  109. {
  110. assert(impl_);
  111. return async_initiate<CompletionToken, void(Ts...)>(
  112. initiate_async_wait{impl_}, token);
  113. }
  114. promise() = delete;
  115. promise(const promise& ) = delete;
  116. promise(promise&& ) noexcept = default;
  117. /// Destruct the promise and cancel the operation.
  118. /**
  119. * It is safe to destruct a promise of a promise that didn't complete.
  120. */
  121. ~promise() { cancel(); }
  122. private:
  123. #if !defined(GENERATING_DOCUMENTATION)
  124. template <typename, typename, typename> friend struct promise;
  125. friend struct detail::promise_handler<void(Ts...), Executor, Allocator>;
  126. #endif // !defined(GENERATING_DOCUMENTATION)
  127. std::shared_ptr<detail::promise_impl<
  128. void(Ts...), Executor, Allocator>> impl_;
  129. promise(
  130. std::shared_ptr<detail::promise_impl<
  131. void(Ts...), Executor, Allocator>> impl)
  132. : impl_(impl)
  133. {
  134. }
  135. struct initiate_async_wait
  136. {
  137. std::shared_ptr<detail::promise_impl<
  138. void(Ts...), Executor, Allocator>> self_;
  139. template <typename WaitHandler>
  140. void operator()(WaitHandler&& handler) const
  141. {
  142. const auto alloc = get_associated_allocator(
  143. handler, self_->get_allocator());
  144. auto cancel = get_associated_cancellation_slot(handler);
  145. if (self_->done)
  146. {
  147. auto exec = asio::get_associated_executor(
  148. handler, self_->get_executor());
  149. asio::post(exec,
  150. [self = std::move(self_),
  151. handler = std::forward<WaitHandler>(handler)]() mutable
  152. {
  153. self->apply(std::move(handler));
  154. });
  155. }
  156. else
  157. {
  158. if (cancel.is_connected())
  159. {
  160. struct cancel_handler
  161. {
  162. std::weak_ptr<detail::promise_impl<
  163. void(Ts...), Executor, Allocator>> self;
  164. cancel_handler(
  165. std::weak_ptr<detail::promise_impl<
  166. void(Ts...), Executor, Allocator>> self)
  167. : self(std::move(self))
  168. {
  169. }
  170. void operator()(cancellation_type level) const
  171. {
  172. if (auto p = self.lock())
  173. {
  174. p->cancel.emit(level);
  175. p->cancel_();
  176. }
  177. }
  178. };
  179. cancel.template emplace<cancel_handler>(self_);
  180. }
  181. self_->set_completion(alloc, std::forward<WaitHandler>(handler));
  182. }
  183. }
  184. };
  185. };
  186. } // namespace experimental
  187. } // namespace asio
  188. #include "asio/detail/pop_options.hpp"
  189. #endif // ASIO_EXPERIMENTAL_PROMISE_HPP