Files
salmanoff/include/adapters/boostAsio/deadlineTimerAReq.h
T
2026-05-30 12:12:59 -04:00

113 lines
2.7 KiB
C++

#ifndef ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H
#define ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H
#include <atomic>
#include <coroutine>
#include <memory>
#include <optional>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/system/error_code.hpp>
namespace adapters::boostAsio {
/** Coroutine awaiter: true if the delay elapsed, false if cancelled/aborted. */
class DeadlineTimerAReq
{
public:
struct AsyncState
{
std::atomic<bool> settled{false};
bool timerExpiredNormally = false;
std::coroutine_handle<> callerSchedHandle;
std::shared_ptr<boost::asio::deadline_timer> timer;
};
DeadlineTimerAReq(
boost::asio::io_context &resumeIoContext,
const boost::posix_time::milliseconds delay,
std::optional<std::shared_ptr<boost::asio::deadline_timer>> &timerOut)
: asyncState(std::make_shared<AsyncState>()),
resumeIoContext(resumeIoContext)
{
asyncState->timer =
std::make_shared<boost::asio::deadline_timer>(resumeIoContext);
timerOut = asyncState->timer;
asyncState->timer->expires_from_now(delay);
asyncState->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> asyncState;
boost::asio::io_context &resumeIoContext;
};
inline auto getDeadlineTimerAReqAwaiter(
boost::asio::io_context &ioContext,
const boost::posix_time::milliseconds delay)
{
std::optional<std::shared_ptr<boost::asio::deadline_timer>> timerOut;
return DeadlineTimerAReq(ioContext, delay, timerOut);
}
inline auto getDeadlineTimerAReqAwaiter(
boost::asio::io_context &ioContext,
const boost::posix_time::milliseconds delay,
std::optional<std::shared_ptr<boost::asio::deadline_timer>> &timerOut)
{
return DeadlineTimerAReq(ioContext, delay, timerOut);
}
} // namespace adapters::boostAsio
#endif // ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H