23namespace Lightweight::Async
30 using OffloadResult = std::invoke_result_t<F&>;
37 class OffloadAwaitable
40 using Result = OffloadResult<F>;
42 OffloadAwaitable(IExecutor& offload, IResumeScheduler& resume, F fn, std::stop_token token):
45 _fn { std::move(fn) },
46 _token { std::move(token) }
50 OffloadAwaitable(OffloadAwaitable&&) =
default;
51 OffloadAwaitable(OffloadAwaitable
const&) =
delete;
52 OffloadAwaitable& operator=(OffloadAwaitable
const&) =
delete;
53 OffloadAwaitable& operator=(OffloadAwaitable&&) =
delete;
54 ~OffloadAwaitable() =
default;
56 [[nodiscard]]
bool await_ready() const noexcept
61 void await_suspend(std::coroutine_handle<> awaiting)
67 if (_token.stop_requested())
69 _error = std::make_exception_ptr(OperationCancelledError {});
70 _resume.Resume(awaiting);
73 _offload.Post([
this, awaiting]()
mutable {
75 _resume.Resume(awaiting);
82 std::rethrow_exception(_error);
83 if constexpr (!std::is_void_v<Result>)
88 if (!_value.has_value())
89 throw std::logic_error {
"OffloadAwaitable: result missing without an error" };
90 return std::move(*_value);
99 if (_token.stop_requested())
100 throw OperationCancelledError {};
101 if constexpr (std::is_void_v<Result>)
104 _value.emplace(_fn());
108 _error = std::current_exception();
113 IResumeScheduler& _resume;
115 std::stop_token _token;
116 std::conditional_t<std::is_void_v<Result>, std::monostate, std::optional<Result>> _value {};
117 std::exception_ptr _error {};
125 template <
typename Awaitable>
126 Task<typename Awaitable::Result> RunOffloadTask(Awaitable awaitable)
128 if constexpr (std::is_void_v<typename Awaitable::Result>)
131 co_return co_await awaitable;
152[[nodiscard]] Task<detail::OffloadResult<F>> Async(IExecutor& offload,
153 IResumeScheduler& resume,
155 std::stop_token token = {})
157 return detail::RunOffloadTask(detail::OffloadAwaitable<F> { offload, resume, std::move(fn), std::move(token) });