#ifndef ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H #define ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H #include #include #include #include #include #include #include #include namespace adapters::boostAsio { /** Coroutine awaiter: true if the delay elapsed, false if cancelled/aborted. * * Reuses the caller-supplied deadline_timer; does not allocate a new timer. */ class DeadlineTimerAReq { public: struct AsyncState { std::atomic settled{false}; bool timerExpiredNormally = false; std::coroutine_handle<> callerSchedHandle; }; DeadlineTimerAReq( boost::asio::io_context &resumeIoContext, boost::asio::deadline_timer &timer, const boost::posix_time::milliseconds delay) : asyncState(std::make_shared()), resumeIoContext(resumeIoContext) { timer.expires_from_now(delay); timer.async_wait( [this](const boost::system::error_code &error) { onTimer(error); }); } bool await_ready() const noexcept { return asyncState->settled.load(std::memory_order_acquire); } bool await_suspend(std::coroutine_handle<> caller) noexcept { if (asyncState->settled.load(std::memory_order_acquire)) { return false; } asyncState->callerSchedHandle = caller; return true; } bool await_resume() const noexcept { return asyncState->timerExpiredNormally; } private: void onTimer(const boost::system::error_code &error) { if (asyncState->settled.exchange(true)) { return; } asyncState->timerExpiredNormally = !error; signalSettledAndResumeCaller(); } void signalSettledAndResumeCaller() { std::coroutine_handle<> handle = asyncState->callerSchedHandle; if (!handle) { return; } boost::asio::post(resumeIoContext, handle); } std::shared_ptr asyncState; boost::asio::io_context &resumeIoContext; }; inline auto getDeadlineTimerAReqAwaiter( boost::asio::io_context &resumeIoContext, boost::asio::deadline_timer &timer, const boost::posix_time::milliseconds delay) { return DeadlineTimerAReq(resumeIoContext, timer, delay); } } // namespace adapters::boostAsio #endif // ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H