123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- //
- // experimental/promise.hpp
- // ~~~~~~~~~~~~~~~~~~~~~~~~
- //
- // Copyright (c) 2021-2023 Klemens D. Morgenstern
- // (klemens dot morgenstern at gmx dot net)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- #ifndef ASIO_EXPERIMENTAL_PROMISE_HPP
- #define ASIO_EXPERIMENTAL_PROMISE_HPP
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- # pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include "asio/detail/config.hpp"
- #include "asio/detail/type_traits.hpp"
- #include "asio/any_io_executor.hpp"
- #include "asio/associated_cancellation_slot.hpp"
- #include "asio/associated_executor.hpp"
- #include "asio/bind_executor.hpp"
- #include "asio/cancellation_signal.hpp"
- #include "asio/dispatch.hpp"
- #include "asio/experimental/impl/promise.hpp"
- #include "asio/post.hpp"
- #include <algorithm>
- #include "asio/detail/push_options.hpp"
- namespace asio {
- namespace experimental {
- template <typename T>
- struct is_promise : std::false_type {};
- template <typename ... Ts>
- struct is_promise<promise<Ts...>> : std::true_type {};
- template <typename T>
- constexpr bool is_promise_v = is_promise<T>::value;
- template <typename ... Ts>
- struct promise_value_type
- {
- using type = std::tuple<Ts...>;
- };
- template <typename T>
- struct promise_value_type<T>
- {
- using type = T;
- };
- template <>
- struct promise_value_type<>
- {
- using type = std::tuple<>;
- };
- #if defined(GENERATING_DOCUMENTATION)
- /// A disposable handle for an eager operation.
- /**
- * @tparam Signature The signature of the operation.
- *
- * @tparam Executor The executor to be used by the promise (taken from the
- * operation).
- *
- * @tparam Allocator The allocator used for the promise. Can be set through
- * use_allocator.
- *
- * A promise can be used to initiate an asynchronous option that can be
- * completed later. If the promise gets destroyed before completion, the
- * operation gets a cancel signal and the result is ignored.
- *
- * A promise fulfills the requirements of async_operation.
- *
- * @par Examples
- * Reading and writing from one coroutine.
- * @code
- * awaitable<void> read_write_some(asio::ip::tcp::socket & sock,
- * asio::mutable_buffer read_buf, asio::const_buffer to_write)
- * {
- * auto p = asio::async_read(read_buf, asio::use_awaitable);
- * co_await asio::async_write_some(to_write, asio::deferred);
- * co_await p;
- * }
- * @endcode
- */
- template<typename Signature = void(),
- typename Executor = asio::any_io_executor,
- typename Allocator = std::allocator<void>>
- struct promise
- #else
- template <typename ... Ts, typename Executor, typename Allocator>
- struct promise<void(Ts...), Executor, Allocator>
- #endif // defined(GENERATING_DOCUMENTATION)
- {
- /// The value that's returned by the promise.
- using value_type = typename promise_value_type<Ts...>::type;
- /// Cancel the promise. Usually done through the destructor.
- void cancel(cancellation_type level = cancellation_type::all)
- {
- if (impl_ && !impl_->done)
- {
- asio::dispatch(impl_->executor,
- [level, impl = impl_]{ impl->cancel.emit(level); });
- }
- }
- /// Check if the promise is completed already.
- bool completed() const noexcept
- {
- return impl_ && impl_->done;
- }
- /// Wait for the promise to become ready.
- template <ASIO_COMPLETION_TOKEN_FOR(void(Ts...)) CompletionToken>
- inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(Ts...))
- operator()(CompletionToken&& token)
- {
- assert(impl_);
- return async_initiate<CompletionToken, void(Ts...)>(
- initiate_async_wait{impl_}, token);
- }
- promise() = delete;
- promise(const promise& ) = delete;
- promise(promise&& ) noexcept = default;
- /// Destruct the promise and cancel the operation.
- /**
- * It is safe to destruct a promise of a promise that didn't complete.
- */
- ~promise() { cancel(); }
- private:
- #if !defined(GENERATING_DOCUMENTATION)
- template <typename, typename, typename> friend struct promise;
- friend struct detail::promise_handler<void(Ts...), Executor, Allocator>;
- #endif // !defined(GENERATING_DOCUMENTATION)
- std::shared_ptr<detail::promise_impl<
- void(Ts...), Executor, Allocator>> impl_;
- promise(
- std::shared_ptr<detail::promise_impl<
- void(Ts...), Executor, Allocator>> impl)
- : impl_(impl)
- {
- }
- struct initiate_async_wait
- {
- std::shared_ptr<detail::promise_impl<
- void(Ts...), Executor, Allocator>> self_;
- template <typename WaitHandler>
- void operator()(WaitHandler&& handler) const
- {
- const auto alloc = get_associated_allocator(
- handler, self_->get_allocator());
- auto cancel = get_associated_cancellation_slot(handler);
- if (self_->done)
- {
- auto exec = asio::get_associated_executor(
- handler, self_->get_executor());
- asio::post(exec,
- [self = std::move(self_),
- handler = std::forward<WaitHandler>(handler)]() mutable
- {
- self->apply(std::move(handler));
- });
- }
- else
- {
- if (cancel.is_connected())
- {
- struct cancel_handler
- {
- std::weak_ptr<detail::promise_impl<
- void(Ts...), Executor, Allocator>> self;
- cancel_handler(
- std::weak_ptr<detail::promise_impl<
- void(Ts...), Executor, Allocator>> self)
- : self(std::move(self))
- {
- }
- void operator()(cancellation_type level) const
- {
- if (auto p = self.lock())
- {
- p->cancel.emit(level);
- p->cancel_();
- }
- }
- };
- cancel.template emplace<cancel_handler>(self_);
- }
- self_->set_completion(alloc, std::forward<WaitHandler>(handler));
- }
- }
- };
- };
- } // namespace experimental
- } // namespace asio
- #include "asio/detail/pop_options.hpp"
- #endif // ASIO_EXPERIMENTAL_PROMISE_HPP
|