From f689a25f65450fa8262d1695a0baa2274b9410f3 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 8 Jul 2024 09:41:19 +0800 Subject: [PATCH] implement async. --- include/Support/Async.h | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/include/Support/Async.h b/include/Support/Async.h index 8b137891..18b88f0d 100644 --- a/include/Support/Async.h +++ b/include/Support/Async.h @@ -1 +1,117 @@ +#pragma once +#include +#include +#include + +namespace clice { + +/// An async coroutine that runs a callback on a worker thread. +template +class async { +private: + Callback callback; + std::optional result; + uv_work_t req; + std::coroutine_handle<> handle; + +public: + template + requires std::is_invocable_v + async(Fn&& fn) : callback(std::forward(fn)) {} + + bool await_ready(this const async& self) noexcept { return false; } + + void await_suspend(this async& self, std::coroutine_handle<> handle) noexcept { + self.handle = handle; + self.req.data = &self; + uv_queue_work( + uv_default_loop(), + &self.req, + [](uv_work_t* req) { + auto& self = *static_cast(req->data); + self.result = self.callback(); + }, + [](uv_work_t* req, int status) { + if(status != 0) { + // TODO: handle error + } + auto& self = *static_cast(req->data); + self->handle.resume(); + }); + } + + decltype(auto) await_resume(this async& self) noexcept { + assert(self.result.has_value()); + return *self.result; + } +}; + +template +async(T) -> async>; + +template +class Task { + struct promise_type { + std::optional value; + + Task get_return_object(this promise_type& self) { + return {std::coroutine_handle::from_promise(self)}; + } + + std::suspend_always initial_suspend() { return {}; } + + std::suspend_always final_suspend() noexcept { return {}; } + + void return_value(this promise_type& self, T&& value) { self.value = std::move(value); } + + void return_value(this promise_type& self, const T& value) { self.value = value; } + + void unhandled_exception() { std::terminate(); } + }; + + std::coroutine_handle handle; + +public: + Task(std::coroutine_handle handle) : handle(handle) {} + + ~Task() { + if(!handle.done()) { + handle.destroy(); + } + } + + T get() { return std::move(handle.promise().value); } +}; + +template <> +class Task { + struct promise_type { + Task get_return_object(this promise_type& self) { + return {std::coroutine_handle::from_promise(self)}; + } + + std::suspend_never initial_suspend() { return {}; } + + std::suspend_never final_suspend() noexcept { return {}; } + + void return_void() {} + + void unhandled_exception() { std::terminate(); } + }; + + std::coroutine_handle handle; + +public: + Task(std::coroutine_handle handle) : handle(handle) {} + + ~Task() { + if(!handle.done()) { + handle.destroy(); + } + } + + void get() {} +}; + +} // namespace clice