11class ViaContinuation {
14 constexpr ViaContinuation get_return_object()
noexcept {
15 return ViaContinuation{std::coroutine_handle<promise_type>::from_promise(*
this)};
17 constexpr std::suspend_always initial_suspend()
noexcept {
return {}; }
18 constexpr std::suspend_never final_suspend()
noexcept {
return {}; }
19 constexpr void return_void()
noexcept {}
20 [[noreturn]]
void unhandled_exception()
noexcept { std::terminate(); }
23 using Handle = std::coroutine_handle<promise_type>;
25 ViaContinuation(ViaContinuation
const&) =
delete;
26 ViaContinuation& operator=(ViaContinuation
const&) =
delete;
28 constexpr explicit ViaContinuation(Handle h) noexcept : handle(h) {}
31 constexpr ~ViaContinuation() {
33 std::exchange(handle,
nullptr).destroy();
37 constexpr std::coroutine_handle<> get() const noexcept {
return handle; }
38 constexpr void release() noexcept { handle =
nullptr; }
48 using Handle = std::coroutine_handle<promise_type>;
52 using ExpectedResult =
typename CoroPromise<T>::ExpectedResult;
59 constexpr explicit CoroTask(Handle h) noexcept : handle(h) {}
64 struct ExpectedAwaiter :
public AwaiterBase {
65 constexpr void setExecutor(ExecutorRef ex) { AwaiterBase::handle.promise().exec = ex; }
66 constexpr ExpectedAwaiter(Handle h) : AwaiterBase(h) {}
67 constexpr ExpectedResult await_resume()
noexcept {
return AwaiterBase::getResult(); }
70 struct ValueAwaiter :
public AwaiterBase {
71 constexpr ValueAwaiter(Handle h) : AwaiterBase(h) {}
72 constexpr T await_resume() {
73 if constexpr (std::is_same_v<T, ExpectedResult>) {
74 return AwaiterBase::getResult();
76 return AwaiterBase::getResult().value();
81 struct ViaAwaiter :
public ValueAwaiter {
82 constexpr ViaAwaiter(Handle h, NonNullExecutorRef executor) : ValueAwaiter(h) {
83 AwaiterBase::handle.promise().exec = executor;
86 template <std::derived_from<CoroPromiseBase> P>
87 void await_suspend(std::coroutine_handle<P> continuation) {
88 auto resumeCaller = [](NonNullExecutorRef executor,
90 executor.execute(continuation);
92 }(continuation.promise().exec.value(), continuation);
93 auto& promise = AwaiterBase::handle.promise();
94 promise.handle = resumeCaller.get();
95 promise.local = continuation.promise().local;
96 promise.exec->execute(AwaiterBase::handle);
97 resumeCaller.release();
105 constexpr std::suspend_never initial_suspend()
noexcept {
return {}; }
106 constexpr std::suspend_never final_suspend()
noexcept {
return {}; }
107 constexpr void return_void()
noexcept {}
108 constexpr void unhandled_exception() { std::rethrow_exception(std::current_exception()); }
109 constexpr Launcher get_return_object()
noexcept {
return {}; }
114 CoroTask(CoroTask
const&) =
delete;
115 CoroTask& operator=(CoroTask
const&) =
delete;
117 CoroTask(CoroTask&& other) noexcept : handle(std::exchange(other.handle,
nullptr)) {}
121 std::exchange(handle,
nullptr).destroy();
125 constexpr void setExecutor(ExecutorRef ex) { handle.promise().exec = ex; }
127 constexpr ExecutorRef getExecutor() {
return handle.promise().exec; }
129 bool done()
const {
return !handle || handle.done(); }
131 auto operator co_await() {
return ValueAwaiter(std::exchange(handle,
nullptr)); }
133 auto via(NonNullExecutorRef executor) {
return ViaAwaiter(std::exchange(handle,
nullptr), executor); }
135 auto tryGet() {
return ExpectedAwaiter(std::exchange(handle,
nullptr)); }
137 template <std::invocable<ExpectedResult> F>
138 void launch(NonNullExecutorRef executor, F&& callback)
noexcept try {
139 setExecutor(executor);
140 [](CoroTask lazy, std::decay_t<F> cb) -> Launcher {
141 std::invoke(cb,
co_await lazy.tryGet());
142 }(std::move(*
this), std::forward<F>(callback));
144 std::invoke(std::forward<F>(callback), makeExceptionError());
146 void launch(NonNullExecutorRef executor)
noexcept {
147 launch(executor, [](
auto&&) {});
149 ExpectedResult syncLaunch(NonNullExecutorRef executor)
noexcept {
150 ExpectedResult value;
151 std::binary_semaphore cond{0};
152 launch(executor, [&](ExpectedResult&& result) {
153 value = std::move(result);