Based on the answer of Turning a function call which takes a callback into a coroutine I'm able to come up with a my version of a generic CallbackAwaiter class that I can inherent and wait for callbacks. However I can't figure out how to make it support symmetric transfer. Causing stack overflow in certain cases (mostly in complicated business logic). My code looks like this
template <typename T>
struct CallbackAwaiter
{
bool await_ready() noexcept
{
return false;
}
const T &await_resume() const noexcept(false)
{
assert(result_.has_value() == true || exception_ != nullptr);
if (exception_)
std::rethrow_exception(exception_);
return result_.value();
}
private:
optional<T> result_;
std::exception_ptr exception_{nullptr};
protected:
void setException(const std::exception_ptr &e)
{
exception_ = e;
}
void setValue(const T &v)
{
result_.emplace(v);
}
void setValue(T &&v)
{
result_.emplace(std::move(v));
}
};
// For example. I can inherent the class and fill in `await_suspend` to convert callbacks into coroutines.
struct SQLAwaiter : CallbackAwaiter<std::map<std::string, std::string>>
{
...
void await_suspend(std::coroutine_handle<> handle)
{
dbClient->runSQL(..., [handle](){
...
setValue(...);
handle.resume();
});
}
};
This works. But by calling handle.resume() manually I don't support symmetric transfer. Which stack overflows after deep corouting resume. So far I tried adding promise_type and using std::noop_coroutine to get symmetric transfer working. For example
std::noop_coroutine_handle await_suspend(std::coroutine_handle<> handle)
{
dbClient->runSQL(..., [handle](){
...
setValue(...);
handle.resume();
});
return std::noop_coroutine{};
}
// and
struct CallbackAwaiter
{
CallbackAwaiter() : coro_(std::noop_coroutine{}) {}
std::coroutine_handle<promise_type> coro_;
}
But obviously these wouldn't work. Returning noop_coroutine doesn't magically make handle.resume() not take up stack space. Nor does adding promise_type would work as there's no compiler generated coroutine.
I'm out of idea. How can I support symmetric transfer for such case?