// // experimental/promise.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2021-2022 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 BOOST_ASIO_EXPERIMENTAL_PROMISE_HPP #define BOOST_ASIO_EXPERIMENTAL_PROMISE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace asio { namespace experimental { template struct use_promise_t {}; constexpr use_promise_t<> use_promise; template struct is_promise : std::false_type {}; template struct is_promise> : std::true_type {}; template constexpr bool is_promise_v = is_promise::value; template struct promise_value_type { using type = std::tuple; }; template struct promise_value_type { using type = T; }; template <> struct promise_value_type<> { using type = std::monostate; }; #if defined(GENERATING_DOCUMENTATION) /// The primary template is not defined. template struct promise { }; #endif // defined(GENERATING_DOCUMENTATION) template struct promise { using value_type = typename promise_value_type::type; using tuple_type = std::tuple; using executor_type = Executor; /// Rebinds the promise type to another executor. template struct rebind_executor { /// The file type when rebound to the specified executor. typedef promise other; }; /// Get the executor of the promise executor_type get_executor() const { if (impl_) return impl_->executor; else return {}; } /// Cancel the promise. Usually done through the destructor. void cancel(cancellation_type level = cancellation_type::all) { if (impl_ && !impl_->done) { boost::asio::dispatch(impl_->executor, [level, impl = impl_]{impl->cancel.emit(level);}); } } /// Check if the promise is completed already. bool complete() const noexcept { return impl_ && impl_->done; } /// Wait for the promise to become ready. template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Ts...)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> auto async_wait(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { assert(impl_); return async_initiate( initiate_async_wait{impl_}, token); } promise() = delete; promise(const promise& ) = delete; promise(promise&& ) noexcept = default; ~promise() { cancel(); } private: #if !defined(GENERATING_DOCUMENTATION) template friend struct promise; friend struct detail::promise_handler; #endif // !defined(GENERATING_DOCUMENTATION) std::shared_ptr> impl_; promise(std::shared_ptr> impl) : impl_(impl) { } struct initiate_async_wait { std::shared_ptr> self_; template void operator()(WaitHandler&& handler) const { const auto exec = get_associated_executor(handler, self_->executor); auto cancel = get_associated_cancellation_slot(handler); if (self_->done) { boost::asio::post(exec, [self = self_, h = std::forward(handler)]() mutable { std::apply(std::forward(h), std::move(*self->result)); }); } else { if (cancel.is_connected()) { struct cancel_handler { std::weak_ptr> self; cancel_handler( std::weak_ptr> self) : self(std::move(self)) { } void operator()(cancellation_type level) const { if (auto p = self.lock(); p != nullptr) p->cancel.emit(level); } }; cancel.template emplace(self_); } self_->completion = {exec, std::forward(handler)}; } } }; }; } // namespace experimental #if !defined(GENERATING_DOCUMENTATION) template struct async_result, R(Args...)> { using handler_type = experimental::detail::promise_handler< void(typename decay::type...), Executor>; using return_type = experimental::promise< void(typename decay::type...), Executor>; template static auto initiate(Initiation initiation, experimental::use_promise_t, InitArgs... args) -> typename handler_type::promise_type { handler_type ht{get_associated_executor(initiation)}; std::move(initiation)(ht, std::move(args)...); return ht.make_promise(); } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include #endif // BOOST_ASIO_EXPERIMENTAL_PROMISE_HPP