12#include <condition_variable>
44template <
typename TResult>
57 return Task(std::coroutine_handle<promise_type>::from_promise(*
this));
77 bool await_ready()
const noexcept {
81 void await_suspend(std::coroutine_handle<promise_type> handle)
const noexcept {
91 std::lock_guard<std::mutex> lock(handle.promise().mutex);
92 handle.promise().completed =
true;
94 handle.promise().ready.notify_all();
101 void await_resume()
const noexcept {}
104 return FinalAwaiter{};
113 result = std::move(value);
120 error = std::current_exception();
153 explicit Task(std::coroutine_handle<promise_type> coroutine) : handle(coroutine) {}
156 Task& operator=(
const Task&) =
delete;
163 Task(
Task&& other) noexcept : handle(std::exchange(other.handle, {})) {}
172 if (
this != &other) {
176 handle = std::exchange(other.handle, {});
190 std::lock_guard<std::mutex> lock(handle.promise().mutex);
191 return handle.promise().completed;
207 throw std::runtime_error(
"Task has no coroutine state");
213 std::unique_lock<std::mutex> lock(handle.promise().mutex);
214 handle.promise().ready.wait(lock, [
this]() {
return handle.promise().completed; });
217 if (handle.promise().error) {
218 std::rethrow_exception(handle.promise().error);
221 return std::move(*handle.promise().result);
233 auto operator co_await() {
235 std::coroutine_handle<promise_type> task_handle;
237 bool await_ready()
const noexcept {
238 return !task_handle || task_handle.promise().completed;
241 void await_suspend(std::coroutine_handle<> awaiting)
const {
247 bool resume_task =
false;
249 std::lock_guard<std::mutex> lock(task_handle.promise().mutex);
250 if (task_handle.promise().completed) {
254 task_handle.promise().continuation = awaiting;
255 resume_task = !task_handle.promise().started;
256 task_handle.promise().started =
true;
261 task_handle.resume();
265 TResult await_resume() {
267 throw std::runtime_error(
"Task has no coroutine state");
270 if (task_handle.promise().error) {
271 std::rethrow_exception(task_handle.promise().error);
274 return std::move(*task_handle.promise().result);
278 return Awaiter{ handle };
283 bool should_resume =
false;
285 std::lock_guard<std::mutex> lock(handle.promise().mutex);
286 should_resume = !handle.promise().started && !handle.promise().completed;
287 handle.promise().started =
true;
294 std::coroutine_handle<promise_type> handle;
The result of an asynchronous StripeKit operation.
Task(std::coroutine_handle< promise_type > coroutine)
Adopts an existing coroutine handle.
bool is_ready() const
Reports whether the value is already available.
TResult result()
Waits for the operation to finish and returns its value.
Task & operator=(Task &&other) noexcept
Takes over another task's coroutine, leaving it empty.
Task()=default
Creates a task with no coroutine attached.
Task(Task &&other) noexcept
Takes over another task's coroutine, leaving it empty.
~Task()
Destroys the task and its coroutine state.
std::suspend_always initial_suspend() noexcept
Suspends the coroutine at its start so the caller controls when it runs.
std::exception_ptr error
The exception that escaped, if one did.
std::condition_variable ready
Signalled when the coroutine finishes.
std::coroutine_handle continuation
Coroutine waiting on this task.
auto final_suspend() noexcept
Wakes anything waiting on this task once it finishes.
std::mutex mutex
Guards the fields below.
void unhandled_exception()
Captures an escaping exception so it can be rethrown to the waiter.
Task get_return_object()
Creates the task object handed back to the caller.
std::optional< TResult > result
The produced value, once available.
void return_value(TResult value)
Stores the value the coroutine returned.
bool completed
True once the coroutine has finished.
bool started
True once the coroutine has been resumed.