2026-05-28 15:17:50 -04:00
|
|
|
#ifndef ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H
|
|
|
|
|
#define ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H
|
|
|
|
|
|
2026-05-28 20:13:12 -04:00
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
#include <coroutine>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
2026-05-28 15:17:50 -04:00
|
|
|
#include <boost/asio/deadline_timer.hpp>
|
2026-05-30 11:59:42 -04:00
|
|
|
#include <boost/asio/io_context.hpp>
|
2026-05-28 20:13:12 -04:00
|
|
|
#include <boost/asio/post.hpp>
|
2026-05-28 15:17:50 -04:00
|
|
|
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
2026-05-28 20:13:12 -04:00
|
|
|
#include <boost/system/error_code.hpp>
|
2026-05-28 15:17:50 -04:00
|
|
|
|
|
|
|
|
namespace adapters::boostAsio {
|
|
|
|
|
|
2026-06-09 11:19:42 -04:00
|
|
|
/** Coroutine awaiter: true if the delay elapsed, false if cancelled/aborted.
|
|
|
|
|
*
|
|
|
|
|
* Reuses the caller-supplied deadline_timer; does not allocate a new timer.
|
|
|
|
|
*/
|
2026-05-28 20:13:12 -04:00
|
|
|
class DeadlineTimerAReq
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
struct AsyncState
|
|
|
|
|
{
|
|
|
|
|
std::atomic<bool> settled{false};
|
|
|
|
|
bool timerExpiredNormally = false;
|
|
|
|
|
std::coroutine_handle<> callerSchedHandle;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeadlineTimerAReq(
|
2026-05-30 11:59:42 -04:00
|
|
|
boost::asio::io_context &resumeIoContext,
|
2026-06-09 11:19:42 -04:00
|
|
|
boost::asio::deadline_timer &timer,
|
|
|
|
|
const boost::posix_time::milliseconds delay)
|
2026-05-28 20:13:12 -04:00
|
|
|
: asyncState(std::make_shared<AsyncState>()),
|
2026-05-30 11:59:42 -04:00
|
|
|
resumeIoContext(resumeIoContext)
|
2026-05-28 20:13:12 -04:00
|
|
|
{
|
2026-06-09 11:19:42 -04:00
|
|
|
timer.expires_from_now(delay);
|
|
|
|
|
timer.async_wait(
|
2026-05-28 20:13:12 -04:00
|
|
|
[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;
|
|
|
|
|
}
|
2026-05-28 15:17:50 -04:00
|
|
|
|
2026-05-28 20:13:12 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-30 11:59:42 -04:00
|
|
|
boost::asio::post(resumeIoContext, handle);
|
2026-05-28 20:13:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<AsyncState> asyncState;
|
2026-05-30 11:59:42 -04:00
|
|
|
boost::asio::io_context &resumeIoContext;
|
2026-05-28 20:13:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline auto getDeadlineTimerAReqAwaiter(
|
2026-06-09 11:19:42 -04:00
|
|
|
boost::asio::io_context &resumeIoContext,
|
|
|
|
|
boost::asio::deadline_timer &timer,
|
2026-05-28 15:17:50 -04:00
|
|
|
const boost::posix_time::milliseconds delay)
|
|
|
|
|
{
|
2026-06-09 11:19:42 -04:00
|
|
|
return DeadlineTimerAReq(resumeIoContext, timer, delay);
|
2026-05-28 15:17:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace adapters::boostAsio
|
|
|
|
|
|
|
|
|
|
#endif // ADAPTERS_BOOST_ASIO_DEADLINE_TIMER_AREQ_H
|