16namespace Lightweight::Async
23 using OffloadResult = std::invoke_result_t<F&>;
30 class OffloadAwaitable
33 using Result = OffloadResult<F>;
35 OffloadAwaitable(IExecutor& offload, IResumeScheduler& resume, F fn, std::stop_token token):
38 _fn { std::move(fn) },
39 _token { std::move(token) }
43 OffloadAwaitable(OffloadAwaitable&&) =
default;
44 OffloadAwaitable(OffloadAwaitable
const&) =
delete;
45 OffloadAwaitable& operator=(OffloadAwaitable
const&) =
delete;
46 OffloadAwaitable& operator=(OffloadAwaitable&&) =
delete;
47 ~OffloadAwaitable() =
default;
49 [[nodiscard]]
bool await_ready() const noexcept
54 void await_suspend(std::coroutine_handle<> awaiting)
60 if (_token.stop_requested())
62 _error = std::make_exception_ptr(OperationCancelledError {});
63 _resume.Resume(awaiting);
66 _offload.Post([
this, awaiting]()
mutable {
68 _resume.Resume(awaiting);
75 std::rethrow_exception(_error);
76 if constexpr (!std::is_void_v<Result>)
81 if (!_value.has_value())
82 throw std::logic_error {
"OffloadAwaitable: result missing without an error" };
83 return std::move(*_value);
92 if (_token.stop_requested())
93 throw OperationCancelledError {};
94 if constexpr (std::is_void_v<Result>)
97 _value.emplace(_fn());
101 _error = std::current_exception();
106 IResumeScheduler& _resume;
108 std::stop_token _token;
109 std::conditional_t<std::is_void_v<Result>, std::monostate, std::optional<Result>> _value {};
110 std::exception_ptr _error {};
118 template <
typename Awaitable>
119 Task<typename Awaitable::Result> RunOffloadTask(Awaitable awaitable)
121 if constexpr (std::is_void_v<typename Awaitable::Result>)
124 co_return co_await awaitable;
145[[nodiscard]] Task<detail::OffloadResult<F>> Async(IExecutor& offload,
146 IResumeScheduler& resume,
148 std::stop_token token = {})
150 return detail::RunOffloadTask(detail::OffloadAwaitable<F> { offload, resume, std::move(fn), std::move(token) });