#ifndef CPS_CALLBACK_AREQ_H #define CPS_CALLBACK_AREQ_H #include #include #include #include #include #include #include namespace smo { namespace cpsBoundary { /** Eager-start CPS callback → coroutine adapter (mirrors * PuppetThread::ViralThreadLifetimeMgmtInvoker). */ template class CpsCallbackAReq { public: struct AsyncState { std::atomic settled{false}; Result result{}; std::coroutine_handle<> callerSchedHandle; }; CpsCallbackAReq( boost::asio::io_service &resumeIoService, StartFn startFn) : asyncState(std::make_shared()), resumeIoService(resumeIoService) { startFn(sscl::cps::Callback{ nullptr, [this](auto &&...args) { storeResult(std::forward(args)...); signalSettledAndResumeCaller(); }}); } bool await_ready() const noexcept { return asyncState->settled.load(std::memory_order_acquire); } bool await_suspend(std::coroutine_handle<> callerSchedHandle) noexcept { if (asyncState->settled.load(std::memory_order_acquire)) { return false; } asyncState->callerSchedHandle = callerSchedHandle; return true; } Result await_resume() noexcept { return asyncState->result; } private: template void storeResult(Args &&...args) { asyncState->result = Result{std::forward(args)...}; } void signalSettledAndResumeCaller() noexcept { asyncState->settled.store(true, std::memory_order_release); std::coroutine_handle<> handle = asyncState->callerSchedHandle; if (!handle) { return; } boost::asio::post( resumeIoService, [handle]() { handle.resume(); }); } std::shared_ptr asyncState; boost::asio::io_service &resumeIoService; }; } // namespace cpsBoundary } // namespace smo #endif // CPS_CALLBACK_AREQ_H