// // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.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_COBALT_PROMISE_HPP #define BOOST_COBALT_PROMISE_HPP #include namespace boost::cobalt { // tag::outline[] template struct [[nodiscard]] promise { promise(promise &&lhs) noexcept; promise& operator=(promise && lhs) noexcept; // enable `co_await`. <1> auto operator co_await (); // Ignore the return value, i.e. detach it. <2> void operator +() &&; // Cancel the promise. void cancel(asio::cancellation_type ct = asio::cancellation_type::all); // Check if the result is ready bool ready() const; // Check if the promise can be awaited. explicit operator bool () const; // <3> // Detach or attach bool attached() const; void detach(); void attach(); // end::outline[] /* tag::outline[] // Create an already completed promimse static promise // Get the return value. If !ready() this function has undefined behaviour. Return get(); end::outline[] */ Return get(const boost::source_location & loc = BOOST_CURRENT_LOCATION) { BOOST_ASSERT(ready()); return receiver_.get_result().value(loc); } using promise_type = detail::cobalt_promise; promise(const promise &) = delete; promise& operator=(const promise &) = delete; ~promise() { if (attached_) cancel(); } constexpr promise(noop n) : receiver_(std::move(n)), attached_(false) {} private: template friend struct detail::cobalt_promise; promise(detail::cobalt_promise * promise) : receiver_(promise->receiver, promise->signal), attached_{true} { } detail::promise_receiver receiver_; bool attached_; friend struct detached; //tag::outline[] }; // end::outline[] template inline promise::promise(promise &&lhs) noexcept : receiver_(std::move(lhs.receiver_)), attached_(std::exchange(lhs.attached_, false)) { } template inline promise& promise::operator=(promise && lhs) noexcept { if (attached_) cancel(); receiver_ = std::move(lhs.receiver_); attached_ = std::exchange(lhs.attached_, false); return *this; } template inline auto promise::operator co_await () {return receiver_.get_awaitable();} // Ignore the returns value template inline void promise::operator +() && {detach();} template inline void promise::cancel(asio::cancellation_type ct) { if (!receiver_.done && *receiver_.reference == &receiver_) receiver_.cancel_signal->emit(ct); } template inline bool promise::ready() const { return receiver_.done; } template inline promise::operator bool () const { return !receiver_.done || !receiver_.result_taken; } template inline bool promise::attached() const {return attached_;} template inline void promise::detach() {attached_ = false;} template inline void promise::attach() {attached_ = true;} } #endif //BOOST_COBALT_PROMISE_HPP