23#include <stdexec/execution.hpp>
25namespace Lightweight::Async
31 template <
typename Receiver,
typename T>
37 struct SenderFinalAwaiter
39 [[nodiscard]]
bool await_ready() const noexcept
44 template <
typename Promise>
45 void await_suspend(std::coroutine_handle<Promise> coro)
const noexcept
47 coro.promise().Complete();
50 void await_resume() const noexcept {}
64 template <
typename Receiver>
65 class SenderPromiseBase
68 std::suspend_always initial_suspend() noexcept
73 SenderFinalAwaiter final_suspend() noexcept
78 void unhandled_exception() noexcept
80 _error = std::current_exception();
86 void BindReceiver(Receiver& receiver)
noexcept
88 _receiver = &receiver;
95 [[nodiscard]]
bool TryDeliverError() noexcept
101 std::rethrow_exception(_error);
103 catch (OperationCancelledError
const&)
105 stdexec::set_stopped(std::move(*_receiver));
109 stdexec::set_error(std::move(*_receiver), std::current_exception());
115 [[nodiscard]] Receiver& BoundReceiver() noexcept
121 Receiver* _receiver =
nullptr;
122 std::exception_ptr _error {};
130 template <
typename Receiver,
typename T>
131 class SenderPromise final:
public SenderPromiseBase<Receiver>
134 SenderDriver<Receiver, T> get_return_object() noexcept;
136 void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>)
138 _result.SetValue(std::move(value));
141 void return_value(T
const& value)
143 _result.SetValue(value);
147 void Complete() noexcept
149 if (!this->TryDeliverError())
150 stdexec::set_value(std::move(this->BoundReceiver()), _result.Take());
154 CoroutineResult<T> _result;
158 template <
typename Receiver>
159 class SenderPromise<Receiver, void> final:
public SenderPromiseBase<Receiver>
162 SenderDriver<Receiver, void> get_return_object() noexcept;
164 void return_void() noexcept {}
167 void Complete() noexcept
169 if (!this->TryDeliverError())
170 stdexec::set_value(std::move(this->BoundReceiver()));
175 template <
typename Receiver,
typename T>
179 using promise_type = SenderPromise<Receiver, T>;
180 using Handle = std::coroutine_handle<promise_type>;
182 explicit SenderDriver(Handle handle)
noexcept:
187 SenderDriver(SenderDriver&& other)
noexcept:
188 _handle { std::exchange(other._handle, {}) }
192 SenderDriver(SenderDriver
const&) =
delete;
193 SenderDriver& operator=(SenderDriver
const&) =
delete;
194 SenderDriver& operator=(SenderDriver&&) =
delete;
203 void Start(Receiver& receiver)
205 _handle.promise().BindReceiver(receiver);
213 template <
typename Receiver,
typename T>
214 SenderDriver<Receiver, T> SenderPromise<Receiver, T>::get_return_object() noexcept
216 return SenderDriver<Receiver, T> { std::coroutine_handle<SenderPromise<Receiver, T>>::from_promise(*
this) };
219 template <
typename Receiver>
220 SenderDriver<Receiver, void> SenderPromise<Receiver, void>::get_return_object() noexcept
222 return SenderDriver<Receiver, void> { std::coroutine_handle<SenderPromise<Receiver, void>>::from_promise(*
this) };
227 template <
typename Receiver,
typename T>
228 SenderDriver<Receiver, T> MakeSenderDriver(Task<T> task)
230 if constexpr (std::is_void_v<T>)
231 co_await std::move(task);
233 co_return co_await std::move(task);
237 template <
typename Receiver,
typename T>
238 class TaskOperationState
241 TaskOperationState(Task<T> task, Receiver receiver):
242 _driver { MakeSenderDriver<Receiver, T>(std::move(task)) },
243 _receiver { std::move(receiver) }
247 TaskOperationState(TaskOperationState
const&) =
delete;
248 TaskOperationState& operator=(TaskOperationState
const&) =
delete;
249 TaskOperationState(TaskOperationState&&) =
delete;
250 TaskOperationState& operator=(TaskOperationState&&) =
delete;
251 ~TaskOperationState() =
default;
255 void start() &
noexcept
257 _driver.Start(_receiver);
261 SenderDriver<Receiver, T> _driver;
269 template <
typename T>
270 struct TaskCompletionSignatures
272 using type = stdexec::completion_signatures<stdexec::set_value_t(T),
273 stdexec::set_error_t(std::exception_ptr),
274 stdexec::set_stopped_t()>;
278 struct TaskCompletionSignatures<void>
280 using type = stdexec::completion_signatures<stdexec::set_value_t(),
281 stdexec::set_error_t(std::exception_ptr),
282 stdexec::set_stopped_t()>;
286 template <
typename T>
290 using sender_concept = stdexec::sender_t;
292 using completion_signatures = TaskCompletionSignatures<T>::type;
294 explicit TaskSender(Task<T> task)
noexcept:
295 _task { std::move(task) }
303 template <
typename Receiver>
304 TaskOperationState<std::decay_t<Receiver>, T> connect(Receiver&& receiver) &&
306 return TaskOperationState<std::decay_t<Receiver>, T> { std::move(_task), std::forward<Receiver>(receiver) };
331[[nodiscard]]
auto AsSender(Task<T> task)
noexcept
333 return detail::TaskSender<T> { std::move(task) };