Add queueInLoopCoro function (#1526)

This commit is contained in:
An Tao 2023-03-09 16:44:34 +08:00 committed by GitHub
parent 314bab0b4c
commit 97a5496fa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 0 deletions

View File

@ -816,5 +816,55 @@ std::function<void()> async_func(Coro &&coro)
async_run(std::move(coro));
};
}
namespace internal
{
template <typename T>
struct [[nodiscard]] EventLoopAwaiter : public drogon::CallbackAwaiter<T>
{
EventLoopAwaiter(std::function<T()> &&task, trantor::EventLoop *loop)
: task_(std::move(task)), loop_(loop)
{
}
void await_suspend(std::coroutine_handle<> handle)
{
loop_->queueInLoop([this, handle]() {
try
{
if constexpr (!std::is_same_v<T, void>)
{
this->setValue(task_());
handle.resume();
}
else
{
task_();
handle.resume();
}
}
catch (const std::exception &err)
{
LOG_ERROR << err.what();
this->setException(std::current_exception());
handle.resume();
}
});
}
private:
std::function<T()> task_;
trantor::EventLoop *loop_;
};
} // namespace internal
/**
* @brief Run a task in a given event loop and returns a resumable object that
* can be co_awaited in a coroutine.
*/
template <typename T>
inline internal::EventLoopAwaiter<T> queueInLoopCoro(trantor::EventLoop *loop,
std::function<T()> task)
{
return internal::EventLoopAwaiter<T>(std::move(task), loop);
}
} // namespace drogon

View File

@ -107,6 +107,14 @@ DROGON_TEST(CroutineBasics)
co_return;
});
CHECK(testVar == 1);
async_run([TEST_CTX]() -> Task<void> {
auto val =
co_await queueInLoopCoro<int>(app().getLoop(), []() { return 42; });
CHECK(val == 42);
});
async_run([TEST_CTX]() -> Task<void> {
co_await queueInLoopCoro<void>(app().getLoop(), []() { LOG_DEBUG; });
});
}
DROGON_TEST(CompilcatedCoroutineLifetime)