diff --git a/3rd/ucoro/LICENSE_1_0.txt b/3rd/psco/LICENSE_1_0.txt similarity index 100% rename from 3rd/ucoro/LICENSE_1_0.txt rename to 3rd/psco/LICENSE_1_0.txt diff --git a/3rd/ucoro/include/ucoro/awaitable.hpp b/3rd/psco/include/psco/awaitable.hpp similarity index 59% rename from 3rd/ucoro/include/ucoro/awaitable.hpp rename to 3rd/psco/include/psco/awaitable.hpp index 9d9f6d9..fb7e654 100644 --- a/3rd/ucoro/include/ucoro/awaitable.hpp +++ b/3rd/psco/include/psco/awaitable.hpp @@ -1,11 +1,9 @@ -// -// Distributed under the Boost Software License, Version 1.0. -// #pragma once #ifdef DISABLE_EXCEPTION #error "DISABLE_EXCEPTION is not supported by ucoro currently" #endif #include +#include #include #include #include @@ -29,10 +27,10 @@ namespace std { using std::experimental::noop_coroutine; using std::experimental::suspend_always; using std::experimental::suspend_never; -} // namespace std +} #endif #else -#error "Compiler version too low to support coroutine !!!" +#error "Compiler version too low to support coroutine" #endif #if defined(DEBUG) || defined(_DEBUG) #if defined(ENABLE_DEBUG_CORO_LEAK) @@ -41,7 +39,7 @@ namespace std { inline std::unordered_set debug_coro_leak; #endif #endif -namespace ucoro { +namespace psco { template struct await_transformer { }; @@ -51,19 +49,7 @@ namespace ucoro { struct awaitable_promise; template struct Callback_Awaiter; - template - struct local_storage_t { - }; - inline constexpr local_storage_t local_storage; namespace concepts { - template - struct local_storage_type_impl : std::false_type { - }; - template - struct local_storage_type_impl> : std::true_type { - }; - template - inline constexpr bool local_storage_type = local_storage_type_impl>::value; template struct awaitable_type_impl : std::false_type { }; @@ -71,7 +57,7 @@ namespace ucoro { struct awaitable_type_impl> : std::true_type { }; template - inline constexpr bool awaitable_type = awaitable_type_impl>::value; + concept awaitable_type = awaitable_type_impl>::value; template struct awaitable_promise_type_impl : std::false_type { }; @@ -79,75 +65,29 @@ namespace ucoro { struct awaitable_promise_type_impl> : std::true_type { }; template - inline constexpr bool awaitable_promise_type = awaitable_promise_type_impl>::value; + concept awaitable_promise_type = awaitable_promise_type_impl>::value; template - inline constexpr bool is_valid_await_suspend_return_value = - std::is_convertible_v> || std::is_void_v || std::is_same_v; - template - struct is_awaiter_impl : std::false_type { + concept valid_await_suspend_return_value = std::convertible_to> || std::is_void_v || std::same_as; + template + concept awaiter = requires(T a) { + { a.await_ready() } -> std::same_as; + { a.await_suspend(std::coroutine_handle<>{}) } -> valid_await_suspend_return_value; + a.await_resume(); }; template - struct is_awaiter_impl().await_ready()), - decltype(std::declval().await_suspend(std::coroutine_handle<>{})), - decltype(std::declval().await_resume())>> - : std::bool_constant< - std::is_same_v().await_ready()), bool> && - is_valid_await_suspend_return_value().await_suspend(std::coroutine_handle<>{}) - )>> { - }; - // MSVC 2019 and some IDE parsers can fail to evaluate the generic SFINAE - // check below for ucoro core awaiters. These explicit specializations keep - // the library traits stable without changing runtime behavior. - template - struct is_awaiter_impl, void> : std::true_type { - }; - template - struct is_awaiter_impl, void> : std::true_type { + concept has_operator_co_await = requires(T a) { + { a.operator co_await() } -> awaiter; }; template - inline constexpr bool is_awaiter_v = is_awaiter_impl>::value; - template - struct has_operator_co_await_impl : std::false_type { + concept awaitable_value = awaiter> || awaitable_type || has_operator_co_await>; + template + concept has_user_defined_await_transformer = requires(T&& a) { + await_transformer>::await_transform(std::move(a)); }; - template - struct has_operator_co_await_impl().operator co_await())>> - : std::bool_constant().operator co_await())>> { - }; - template - inline constexpr bool has_operator_co_await = has_operator_co_await_impl>::value; - template - inline constexpr bool is_awaitable_v = - is_awaiter_v> || awaitable_type || has_operator_co_await>; - template - struct has_user_defined_await_transformer_impl : std::false_type { - }; - template - struct has_user_defined_await_transformer_impl>::await_transform( - std::declval()))>> : std::true_type { - }; - template - inline constexpr bool has_user_defined_await_transformer = - has_user_defined_await_transformer_impl::value; - template - struct is_not_awaitable : std::false_type { - }; - } // namespace concepts + template + concept completion_handler_for = std::invocable; + } namespace traits { - template typename FromTemplate> - struct template_parameter_traits; - template typename ClassTemplate, typename TemplateParameter> - struct template_parameter_traits, ClassTemplate> { - using template_parameter = TemplateParameter; - }; - template typename FromTemplate> - using template_parameter_of = typename template_parameter_traits< - std::decay_t, FromTemplate>::template_parameter; - template - using local_storage_value_type = template_parameter_of; - template - using awaitable_return_type = template_parameter_of; template struct exception_with_result { using type = std::variant; @@ -158,7 +98,7 @@ namespace ucoro { }; template using exception_with_result_t = typename exception_with_result::type; - } // namespace traits + } struct debug_coro_promise { #if defined(DEBUG_CORO_PROMISE_LEAK) void* operator new(std::size_t size) { @@ -186,11 +126,14 @@ namespace ucoro { } T get_value() { if (std::holds_alternative(value_)) { - std::rethrow_exception(std::get(value_)); + auto exception = std::get(value_); + if (exception) { + std::rethrow_exception(exception); + } } return std::move(std::get(value_)); } - std::variant value_{std::exception_ptr{}}; + std::variant value_{std::in_place_index<0>, std::exception_ptr{}}; }; template <> struct awaitable_promise_value { @@ -220,10 +163,6 @@ namespace ucoro { std::lock_guard lock(mutex_); return static_cast(handle_) && !completed_; } - [[nodiscard]] bool has_handle() const noexcept { - std::lock_guard lock(mutex_); - return static_cast(handle_); - } [[nodiscard]] bool started() const noexcept { std::lock_guard lock(mutex_); return started_; @@ -240,7 +179,7 @@ namespace ucoro { std::lock_guard lock(mutex_); started_ = true; } - void request_abandon() noexcept { + void cancel() noexcept { std::shared_ptr child; { std::lock_guard lock(mutex_); @@ -248,7 +187,7 @@ namespace ucoro { child = child_.lock(); } if (child) { - child->request_abandon(); + child->cancel(); } } void set_child(const std::shared_ptr& child) noexcept { @@ -259,7 +198,7 @@ namespace ucoro { cancel_child = cancel_requested_; } if (cancel_child && child) { - child->request_abandon(); + child->cancel(); } } void start() noexcept { @@ -342,20 +281,13 @@ namespace ucoro { } } else { - // The coroutine is already running and may be suspended inside an - // external callback. Do not destroy the frame here. Mark it as - // cancelled and let the callback resume it once so it can unwind to - // final_suspend(), where the frame is destroyed safely. cancel_requested_ = true; destroy_on_completion_ = true; child = child_.lock(); } } if (child) { - child->request_abandon(); - } - if (!handle) { - return; + child->cancel(); } if (handle) { handle.destroy(); @@ -364,7 +296,7 @@ namespace ucoro { [[nodiscard]] bool complete_in_final_suspend() noexcept { std::lock_guard lock(mutex_); completed_ = true; - const bool needs_deferred_finish = cancel_requested_ || destroy_on_completion_ || resume_in_progress_; + bool needs_deferred_finish = cancel_requested_ || destroy_on_completion_ || resume_in_progress_; resume_in_progress_ = needs_deferred_finish; return needs_deferred_finish; } @@ -395,9 +327,7 @@ namespace ucoro { struct final_resume_task { struct promise_type { final_resume_task get_return_object() noexcept { - return final_resume_task{ - std::coroutine_handle::from_promise(*this) - }; + return final_resume_task{std::coroutine_handle::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; @@ -466,67 +396,40 @@ namespace ucoro { auto final_suspend() noexcept { return final_awaitable{this}; } - auto initial_suspend() { + auto initial_suspend() noexcept { return std::suspend_always{}; } - void set_local(std::any local) { - local_ = std::make_shared(std::move(local)); - } - template - struct local_storage_awaiter { - const awaitable_promise* this_; - [[nodiscard]] constexpr bool await_ready() const noexcept { return true; } - constexpr void await_suspend(std::coroutine_handle<>) const noexcept { - } - auto await_resume() const { - if (!this_->local_) { - throw std::logic_error("ucoro local_storage is not set"); - } - if constexpr (std::is_void_v) { - return *this_->local_; - } - else { - return std::any_cast(*this_->local_); - } - } - }; template auto await_transform(A&& awaiter) const { - if constexpr (concepts::local_storage_type>) { - return local_storage_awaiter>>{this}; + if constexpr (concepts::has_user_defined_await_transformer) { + return await_transformer>::await_transform(std::forward(awaiter)); } - else if constexpr (concepts::has_user_defined_await_transformer) { - return await_transformer>::await_transform(std::move(awaiter)); - } - else if constexpr (concepts::is_awaitable_v) { - static_assert(std::is_rvalue_reference_v, "co_await must be used on rvalue"); + else if constexpr (concepts::awaitable_value) { + static_assert(std::is_rvalue_reference_v, "co_await must use an rvalue awaitable"); return std::forward(awaiter); } else { - static_assert(concepts::is_not_awaitable::value, "co_await must be called on an awaitable type"); + static_assert(!std::is_same_v, "co_await expression is not awaitable"); } } std::coroutine_handle<> parent_{}; std::shared_ptr parent_control_{}; std::shared_ptr control_{std::make_shared()}; - std::shared_ptr local_{}; }; template struct awaitable { using promise_type = awaitable_promise; - explicit awaitable(std::coroutine_handle h) - : control_(h.promise().control_) { + explicit awaitable(std::coroutine_handle h) : control_(h.promise().control_) { } ~awaitable() noexcept { reset(); } - awaitable(awaitable&& t) noexcept - : control_(std::move(t.control_)) { + awaitable(awaitable&& other) noexcept : control_(std::move(other.control_)) { } - awaitable& operator=(awaitable&& t) noexcept { - if (&t != this) { + awaitable& operator=(awaitable&& other) noexcept { + if (&other != this) { reset(); - control_ = std::move(t.control_); + control_ = std::move(other.control_); } return *this; } @@ -548,9 +451,6 @@ namespace ucoro { auto await_suspend(std::coroutine_handle continuation) { auto handle = typed_handle(); if constexpr (concepts::awaitable_promise_type) { - handle.promise().local_ = handle.promise().local_ - ? handle.promise().local_ - : continuation.promise().local_; handle.promise().parent_control_ = continuation.promise().control_; continuation.promise().control_->set_child(control_); } @@ -563,13 +463,10 @@ namespace ucoro { [[nodiscard]] bool valid() const noexcept { return control_ && control_->valid(); } - void request_abandon() noexcept { - if (control_) { - control_->request_abandon(); - } - } void cancel() noexcept { - request_abandon(); + if (control_) { + control_->cancel(); + } } void reset() noexcept { if (control_) { @@ -588,56 +485,12 @@ namespace ucoro { control_.reset(); } } - void set_local(std::any local) { - auto handle = typed_handle(); - assert("local has value" && !handle.promise().local_); - handle.promise().set_local(std::move(local)); - } - auto detach(std::any local = {}) { - auto launched_coro = [](awaitable lazy) mutable -> awaitable { - co_return co_await std::move(lazy); - }(std::move(*this)); - if (local.has_value()) { - launched_coro.set_local(local); - } - return launched_coro; - } - template >>> - auto detach_with_callback(Function completion_handler) { - return detach_with_callback(std::any{}, std::move(completion_handler)); - } - template >>> - auto detach_with_callback(std::any local, Function completion_handler) { - auto launched_coro = [](awaitable lazy, auto completion_handler) mutable -> awaitable { - using result_wrapper = ucoro::traits::exception_with_result_t; - result_wrapper result{}; - try { - if constexpr (std::is_void_v) { - co_await std::move(lazy); - result = nullptr; - } - else { - result = result_wrapper{co_await std::move(lazy)}; - } - } - catch (...) { - result = result_wrapper{std::current_exception()}; - } - completion_handler(std::move(result)); - }(std::move(*this), std::move(completion_handler)); - if (local.has_value()) { - launched_coro.set_local(local); - } - return launched_coro; - } std::shared_ptr control_; private: [[nodiscard]] std::coroutine_handle typed_handle() const noexcept { - assert(control_ && "awaitable has no coroutine control block"); + assert(control_); auto handle = control_->handle(); - assert(handle && "awaitable has no coroutine handle"); + assert(handle); return std::coroutine_handle::from_address(handle.address()); } }; @@ -647,8 +500,6 @@ namespace ucoro { control_->attach(handle); return awaitable{handle}; } -} // namespace ucoro -namespace ucoro { template struct Callback_Awaiter_State { std::mutex mutex_; @@ -670,16 +521,14 @@ namespace ucoro { }; template struct Callback_Awaiter { + explicit Callback_Awaiter(CallbackFunction&& callback_function) : callback_function_(std::forward(callback_function)) { + } Callback_Awaiter(const Callback_Awaiter&) = delete; Callback_Awaiter& operator=(const Callback_Awaiter&) = delete; - public: - explicit Callback_Awaiter(CallbackFunction&& callback_function) - : callback_function_(std::forward(callback_function)) { - } Callback_Awaiter(Callback_Awaiter&&) noexcept = default; Callback_Awaiter& operator=(Callback_Awaiter&&) noexcept = default; ~Callback_Awaiter() { - cancel_state(); + cancel_state(state_); } constexpr bool await_ready() noexcept { return false; @@ -707,8 +556,8 @@ namespace ucoro { }); } else { - callback_function_([state](T t) mutable { - complete_state(state, std::move(t)); + callback_function_([state](T value) mutable { + complete_state(state, std::move(value)); }); } } @@ -718,12 +567,7 @@ namespace ucoro { } { std::lock_guard lock(state->mutex_); - if (state->completed_) { - // The callback completed before await_suspend returned. The coroutine - // must not suspend; await_resume() will consume the stored result. - return false; - } - if (state->cancelled_) { + if (state->completed_ || state->cancelled_) { return false; } state->await_suspend_finished_ = true; @@ -731,7 +575,7 @@ namespace ucoro { return true; } T await_resume() { - assert(state_ && "callback awaiter has no state"); + assert(state_); { std::lock_guard lock(state_->mutex_); if (state_->cancelled_) { @@ -747,21 +591,17 @@ namespace ucoro { return; } else { - assert(state_->result_.has_value() && "callback result was not set before await_resume"); + assert(state_->result_.has_value()); return std::move(*state_->result_); } } private: using State = Callback_Awaiter_State; static void cancel_state(const std::shared_ptr& state) noexcept { - if (!state) { - return; + if (state) { + std::lock_guard lock(state->mutex_); + state->cancelled_ = true; } - std::lock_guard lock(state->mutex_); - state->cancelled_ = true; - } - void cancel_state() noexcept { - cancel_state(state_); } static void resume_state(const std::shared_ptr& state) { std::shared_ptr owner; @@ -785,12 +625,10 @@ namespace ucoro { } template static void complete_state(const std::shared_ptr& state, V&& value) { - const bool owner_cancelled = [&]() noexcept { - if (auto owner = state->owner_.lock()) { - return owner->cancel_requested(); - } - return false; - }(); + bool owner_cancelled = false; + if (auto owner = state->owner_.lock()) { + owner_cancelled = owner->cancel_requested(); + } { std::lock_guard lock(state->mutex_); if (state->completed_ || state->cancelled_) { @@ -807,12 +645,10 @@ namespace ucoro { resume_state(state); } static void complete_state(const std::shared_ptr& state) { - const bool owner_cancelled = [&]() noexcept { - if (auto owner = state->owner_.lock()) { - return owner->cancel_requested(); - } - return false; - }(); + bool owner_cancelled = false; + if (auto owner = state->owner_.lock()) { + owner_cancelled = owner->cancel_requested(); + } { std::lock_guard lock(state->mutex_); if (state->completed_ || state->cancelled_) { @@ -828,71 +664,55 @@ namespace ucoro { CallbackFunction callback_function_; std::shared_ptr state_; }; - template - [[nodiscard]] auto callback_awaitable(callback&& cb) -> awaitable { - co_return co_await Callback_Awaiter{std::forward(cb)}; + template + [[nodiscard]] awaitable callback_awaitable(Callback&& callback) { + co_return co_await Callback_Awaiter{std::forward(callback)}; } - template - [[nodiscard]] auto coro_start(Awaitable&& coro, Local&& local, CompleteFunction completer) { - auto launched_coro = coro.detach_with_callback(std::forward(local), std::move(completer)); - launched_coro.start(); - return launched_coro; + template + requires concepts::completion_handler_for> + [[nodiscard]] awaitable with_callback(awaitable task, CompleteFunction completion_handler) { + using result_type = traits::exception_with_result_t; + result_type result{}; + try { + if constexpr (std::is_void_v) { + co_await std::move(task); + result = nullptr; + } + else { + result.template emplace(co_await std::move(task)); + } + } + catch (...) { + if constexpr (std::is_void_v) { + result = std::current_exception(); + } + else { + result.template emplace(std::current_exception()); + } + } + completion_handler(std::move(result)); + co_return; } - template - [[nodiscard]] auto coro_start(Awaitable&& coro, Local&& local) { - auto launched_coro = coro.detach(std::forward(local)); - launched_coro.start(); - return launched_coro; - } - template - [[nodiscard]] auto coro_start(Awaitable&& coro) { - auto launched_coro = coro.detach(); - launched_coro.start(); - return launched_coro; - } - template - void start_detached(Awaitable&& coro, Local&& local, CompleteFunction completer) { - auto launched_coro = coro.detach_with_callback(std::forward(local), std::move(completer)); - launched_coro.start_detached(); - } - template - void start_detached(Awaitable&& coro, Local&& local) { - auto launched_coro = coro.detach(std::forward(local)); - launched_coro.start_detached(); - } - template - void start_detached(Awaitable&& coro) { - auto launched_coro = coro.detach(); - launched_coro.start_detached(); - } - // Synchronously waits until the ucoro task completes and returns its result. - // - // Usage: - // int value = ucoro::sync_await(make_ucoro_task()); - // int value = ucoro::sync_await(make_ucoro_task(), std::string{"request-local"}); - // - // This function blocks the current thread with a condition_variable. It is valid for - // tasks whose completion callback is invoked from another thread, or for tasks that - // finish synchronously. It does not run an event loop. Do not use it to wait for work - // that requires the current thread to pump asio, drogon, Qt, libuv, or another loop. template - auto sync_await(awaitable lazy, std::any local_ = {}) -> T { - std::mutex mtx; + auto sync_await(awaitable task) -> T { + std::mutex mutex; std::condition_variable cv; bool done = false; - traits::exception_with_result_t result; - auto launched_coro = lazy.detach_with_callback(local_, [&](traits::exception_with_result_t result_) mutable { + traits::exception_with_result_t result{}; + auto launched = with_callback(std::move(task), [&](traits::exception_with_result_t value) mutable { { - std::lock_guard lock(mtx); - result = std::move(result_); + std::lock_guard lock(mutex); + result = std::move(value); done = true; } cv.notify_one(); }); - launched_coro.start(); + launched.start(); { - std::unique_lock lock(mtx); - cv.wait(lock, [&] { return done; }); + std::unique_lock lock(mutex); + cv.wait(lock, [&] { + return done; + }); } if constexpr (std::is_void_v) { if (result) { @@ -902,9 +722,12 @@ namespace ucoro { } else { if (std::holds_alternative(result)) { - std::rethrow_exception(std::get(result)); + auto exception = std::get(result); + if (exception) { + std::rethrow_exception(exception); + } } return std::move(std::get(result)); } } -} // namespace ucoro +} diff --git a/3rd/ucoro/include/ucoro/single_thread.h b/3rd/psco/include/psco/single_thread.h similarity index 95% rename from 3rd/ucoro/include/ucoro/single_thread.h rename to 3rd/psco/include/psco/single_thread.h index 4e22ec4..419789a 100644 --- a/3rd/ucoro/include/ucoro/single_thread.h +++ b/3rd/psco/include/psco/single_thread.h @@ -8,10 +8,10 @@ #include #include #include "awaitable.hpp" -namespace ucoro { +namespace psco { class Single_Thread_Scheduler { private: - using Abandoned_Task = ucoro::awaitable; + using Abandoned_Task = psco::awaitable; public: Single_Thread_Scheduler(); ~Single_Thread_Scheduler(); @@ -71,7 +71,7 @@ namespace ucoro { cleanup_abandoned_tasks_locked(garbage); for (auto it = tasks.begin(); it != tasks.end();) { if (it->second.valid()) { - it->second.request_abandon(); + it->second.cancel(); abandoned_tasks_.emplace_back(std::move(it->second)); } it = tasks.erase(it); @@ -81,4 +81,4 @@ namespace ucoro { } cv_.notify_one(); } -} // namespace ucoro +} diff --git a/3rd/ucoro/main.cmake b/3rd/psco/main.cmake similarity index 100% rename from 3rd/ucoro/main.cmake rename to 3rd/psco/main.cmake diff --git a/3rd/ucoro/src/single_thread.cpp b/3rd/psco/src/single_thread.cpp similarity index 91% rename from 3rd/ucoro/src/single_thread.cpp rename to 3rd/psco/src/single_thread.cpp index 92c6a0b..6e255b5 100644 --- a/3rd/ucoro/src/single_thread.cpp +++ b/3rd/psco/src/single_thread.cpp @@ -1,6 +1,6 @@ -#include "ucoro/single_thread.h" +#include "psco/single_thread.h" #include -namespace ucoro { +namespace psco { Single_Thread_Scheduler::Single_Thread_Scheduler() = default; Single_Thread_Scheduler::~Single_Thread_Scheduler() = default; void Single_Thread_Scheduler::reset() { @@ -19,13 +19,8 @@ namespace ucoro { } } else { - // Abandoned tasks from a previous run may still be suspended on - // async_wait(). Do not discard their waiters; release them so they - // can observe cancellation and unwind. release_waiters_locked(); } - // garbage is destroyed outside mtx_, so coroutine frames are never destroyed - // while the scheduler lock is held. } void Single_Thread_Scheduler::post(std::function fn) { { @@ -139,7 +134,6 @@ namespace ucoro { std::lock_guard g(mtx_); cleanup_abandoned_tasks_locked(garbage); } - // garbage is destroyed outside mtx_. } std::size_t Single_Thread_Scheduler::abandoned_task_count() { std::vector garbage; @@ -158,7 +152,7 @@ namespace ucoro { try { std::rethrow_exception(exception); } - catch (const ucoro::operation_cancelled&) { + catch (const psco::operation_cancelled&) { return true; } catch (...) { @@ -182,4 +176,4 @@ namespace ucoro { } } } -} // namespace ucoro +} diff --git a/3rd/ucoro/tests/single_thread_scheduler_tests.cpp b/3rd/psco/tests/single_thread_scheduler_tests.cpp similarity index 95% rename from 3rd/ucoro/tests/single_thread_scheduler_tests.cpp rename to 3rd/psco/tests/single_thread_scheduler_tests.cpp index e24e867..3c17d3f 100644 --- a/3rd/ucoro/tests/single_thread_scheduler_tests.cpp +++ b/3rd/psco/tests/single_thread_scheduler_tests.cpp @@ -1,4 +1,4 @@ -#include "ucoro/single_thread.h" +#include "psco/single_thread.h" #include #include #include @@ -13,10 +13,10 @@ #include #include namespace { - using Scheduler = ucoro::Single_Thread_Scheduler; + using Scheduler = psco::Single_Thread_Scheduler; std::exception_ptr make_operation_cancelled_exception() { try { - throw ucoro::operation_cancelled{}; + throw psco::operation_cancelled{}; } catch (...) { return std::current_exception(); @@ -30,12 +30,12 @@ namespace { return std::current_exception(); } } - ucoro::awaitable scheduler_wait_task( + psco::awaitable scheduler_wait_task( Scheduler& scheduler, std::atomic& stage ) { stage.store(1, std::memory_order_release); - co_await ucoro::callback_awaitable([&scheduler](auto done) mutable { + co_await psco::callback_awaitable([&scheduler](auto done) mutable { scheduler.async_wait([done = std::move(done)]() mutable { done(); }); @@ -43,7 +43,7 @@ namespace { stage.store(2, std::memory_order_release); co_return; } - ucoro::awaitable scheduler_wait_then_return_task( + psco::awaitable scheduler_wait_then_return_task( Scheduler& scheduler ) { std::atomic ignored{0}; @@ -70,7 +70,7 @@ namespace { } } }; - ucoro::awaitable task_with_destructor_that_posts( + psco::awaitable task_with_destructor_that_posts( Scheduler& scheduler, std::atomic& stage, std::atomic& destructor_posted_callbacks @@ -81,7 +81,7 @@ namespace { } void expect_operation_cancelled(std::exception_ptr exception) { ASSERT_TRUE(exception != nullptr); - EXPECT_THROW(std::rethrow_exception(exception), ucoro::operation_cancelled); + EXPECT_THROW(std::rethrow_exception(exception), psco::operation_cancelled); } } TEST(SingleThreadSchedulerTest, CompileTimeProperties) { @@ -345,8 +345,8 @@ TEST(SingleThreadSchedulerTest, AbandonRemainingTasksKeepsTaskUntilReleasedByWai std::condition_variable cv; bool completed = false; std::exception_ptr exception; - std::map> tasks; - auto task = scheduler_wait_task(scheduler, stage).detach_with_callback( + std::map> tasks; + auto task = psco::with_callback(scheduler_wait_task(scheduler, stage), [&](std::exception_ptr result) { { std::lock_guard lock(mutex); @@ -380,8 +380,8 @@ TEST(SingleThreadSchedulerTest, ResetDoesNotDiscardAbandonedCallbacks) { std::condition_variable cv; bool completed = false; std::exception_ptr exception; - std::map> tasks; - auto task = scheduler_wait_task(scheduler, stage).detach_with_callback( + std::map> tasks; + auto task = psco::with_callback(scheduler_wait_task(scheduler, stage), [&](std::exception_ptr result) { { std::lock_guard lock(mutex); @@ -410,7 +410,7 @@ TEST(SingleThreadSchedulerTest, CleanupAbandonedTasksDoesNotDestroyCoroutineFram Scheduler scheduler; std::atomic stage{0}; std::atomic destructor_posted_callbacks{0}; - std::map> tasks; + std::map> tasks; auto task = task_with_destructor_that_posts( scheduler, stage, diff --git a/3rd/ucoro/tests/ucoro_tests.cpp b/3rd/psco/tests/ucoro_tests.cpp similarity index 71% rename from 3rd/ucoro/tests/ucoro_tests.cpp rename to 3rd/psco/tests/ucoro_tests.cpp index 94fc661..ec8437f 100644 --- a/3rd/ucoro/tests/ucoro_tests.cpp +++ b/3rd/psco/tests/ucoro_tests.cpp @@ -1,4 +1,4 @@ -#include "ucoro/awaitable.hpp" +#include "psco/awaitable.hpp" #include #include #include @@ -88,58 +88,51 @@ namespace { NonDefaultValue& operator=(NonDefaultValue&&) noexcept = default; int value; }; - ucoro::awaitable compute_callback_sync(int value) { - auto ret = co_await ucoro::callback_awaitable([value](auto handler) { + psco::awaitable compute_callback_sync(int value) { + auto ret = co_await psco::callback_awaitable([value](auto handler) { handler(value * 100); }); co_return value + ret; } - ucoro::awaitable compute_callback_async(Simulated_Async_Callbacks& async, int value) { - auto ret = co_await ucoro::callback_awaitable([&async, value](auto handler) { + psco::awaitable compute_callback_async(Simulated_Async_Callbacks& async, int value) { + auto ret = co_await psco::callback_awaitable([&async, value](auto handler) { async.async_int(value, std::move(handler)); }); co_return value + ret; } - ucoro::awaitable compute_callback_async_void(Simulated_Async_Callbacks& async, std::atomic& flag) { - co_await ucoro::callback_awaitable([&async, &flag](auto handler) { + psco::awaitable compute_callback_async_void(Simulated_Async_Callbacks& async, std::atomic& flag) { + co_await psco::callback_awaitable([&async, &flag](auto handler) { async.async_void([&flag, handler = std::move(handler)]() mutable { flag.store(1, std::memory_order_release); handler(); }); }); + co_return; } - ucoro::awaitable compute_non_default_value(Simulated_Async_Callbacks& async) { - auto value = co_await ucoro::callback_awaitable([&async](auto handler) { + psco::awaitable compute_non_default_value(Simulated_Async_Callbacks& async) { + auto value = co_await psco::callback_awaitable([&async](auto handler) { async.async_value(NonDefaultValue{42}, std::move(handler)); }); co_return value.value; } - ucoro::awaitable read_local_string() { - co_return co_await ucoro::local_storage_t{}; - } - ucoro::awaitable> read_parent_and_detached_local() { - auto inherited = co_await read_local_string(); - auto detached = co_await read_local_string().detach(std::string{"detached-local"}); - co_return std::pair{std::move(inherited), std::move(detached)}; - } - ucoro::awaitable throw_int_task() { + psco::awaitable throw_int_task() { throw std::runtime_error("int-task-error"); co_return 1; } - ucoro::awaitable throw_void_task() { + psco::awaitable throw_void_task() { throw std::runtime_error("void-task-error"); co_return; } - ucoro::awaitable> make_unique_value() { + psco::awaitable> make_unique_value() { co_return std::make_unique(77); } - ucoro::awaitable recursive_task(int value) { + psco::awaitable recursive_task(int value) { if (value == 0) { co_return; } co_await recursive_task(value - 1); } - ucoro::awaitable mark_on_run(std::atomic& flag) { + psco::awaitable mark_on_run(std::atomic& flag) { flag.fetch_add(1, std::memory_order_acq_rel); co_return; } @@ -157,36 +150,29 @@ namespace { live_count().fetch_sub(1, std::memory_order_acq_rel); } }; - ucoro::awaitable sync_probe_task() { + psco::awaitable sync_probe_task() { AllocationProbe probe; co_return; } - ucoro::awaitable async_probe_task(Simulated_Async_Callbacks& async) { + psco::awaitable async_probe_task(Simulated_Async_Callbacks& async) { AllocationProbe probe; - co_await ucoro::callback_awaitable([&async](auto handler) { + co_await psco::callback_awaitable([&async](auto handler) { async.async_void(std::move(handler)); }); + co_return; } - ucoro::awaitable manual_probe_task(Manual_Async_Callbacks& async, std::atomic& after_await) { + psco::awaitable manual_probe_task(Manual_Async_Callbacks& async, std::atomic& after_await) { AllocationProbe probe; - auto value = co_await ucoro::callback_awaitable([&async](auto handler) { + auto value = co_await psco::callback_awaitable([&async](auto handler) { async.async_int(std::move(handler)); }); after_await.store(value, std::memory_order_release); + co_return; } void compile_time_checks() { - static_assert(ucoro::concepts::local_storage_type>, - "local_storage_t check failed"); - using local_storage_template_parameter = ucoro::traits::template_parameter_of< - decltype(ucoro::local_storage), ucoro::local_storage_t>; - static_assert(std::is_void_v, - "local_storage should be local_storage_t"); - // Keep this test limited to stable library traits. MSVC 2019 has fragile parsing for - // static_assert checks involving coroutine awaiter SFINAE and generic lambdas. Runtime - // tests below cover CallbackAwaiter and awaitable behavior directly. - static_assert(ucoro::concepts::awaitable_type>, + static_assert(psco::concepts::awaitable_type>, "awaitable should be ucoro awaitable"); - static_assert(!ucoro::concepts::awaitable_type, "int should not be ucoro awaitable"); + static_assert(!psco::concepts::awaitable_type, "int should not be ucoro awaitable"); } } TEST(UcoroTest, CompileTimeTraitsMatchCoreTypes) { @@ -194,30 +180,26 @@ TEST(UcoroTest, CompileTimeTraitsMatchCoreTypes) { SUCCEED(); } TEST(UcoroTest, CallbackAwaitableCanCompleteSynchronously) { - EXPECT_EQ(ucoro::sync_await(compute_callback_sync(2)), 202); + EXPECT_EQ(psco::sync_await(compute_callback_sync(2)), 202); } TEST(UcoroTest, SyncAwaitWaitsForSimulatedAsyncThreadCallback) { Simulated_Async_Callbacks async; - EXPECT_EQ(ucoro::sync_await(compute_callback_async(async, 3)), 303); + EXPECT_EQ(psco::sync_await(compute_callback_async(async, 3)), 303); } TEST(UcoroTest, CallbackAwaitableSupportsVoidCompletion) { Simulated_Async_Callbacks async; std::atomic flag{0}; - ucoro::sync_await(compute_callback_async_void(async, flag)); + psco::sync_await(compute_callback_async_void(async, flag)); EXPECT_EQ(flag.load(std::memory_order_acquire), 1); } TEST(UcoroTest, CallbackAwaiterSupportsNonDefaultConstructibleValue) { Simulated_Async_Callbacks async; - EXPECT_EQ(ucoro::sync_await(compute_non_default_value(async)), 42); -} -TEST(UcoroTest, DetachLocalOverridesParentLocalWhenAwaited) { - auto values = ucoro::sync_await(read_parent_and_detached_local(), std::string{"parent-local"}); - EXPECT_EQ(values.first, "parent-local"); - EXPECT_EQ(values.second, "detached-local"); + EXPECT_EQ(psco::sync_await(compute_non_default_value(async)), 42); } + TEST(UcoroTest, LateDuplicateCallbackAfterAwaiterDestructionIsIgnored) { std::thread late_callback; - auto value = ucoro::sync_await(ucoro::callback_awaitable([&late_callback](auto handler) mutable { + auto value = psco::sync_await(psco::callback_awaitable([&late_callback](auto handler) mutable { handler(11); late_callback = std::thread([handler = std::move(handler)]() mutable { std::this_thread::sleep_for(std::chrono::milliseconds(10)); @@ -230,18 +212,18 @@ TEST(UcoroTest, LateDuplicateCallbackAfterAwaiterDestructionIsIgnored) { } } TEST(UcoroTest, SyncAwaitRethrowsIntTaskException) { - EXPECT_THROW(static_cast(ucoro::sync_await(throw_int_task())), std::runtime_error); + EXPECT_THROW(static_cast(psco::sync_await(throw_int_task())), std::runtime_error); } TEST(UcoroTest, SyncAwaitRethrowsVoidTaskException) { - EXPECT_THROW(ucoro::sync_await(throw_void_task()), std::runtime_error); + EXPECT_THROW(psco::sync_await(throw_void_task()), std::runtime_error); } TEST(UcoroTest, AwaitableReturnsMoveOnlyValue) { - auto value = ucoro::sync_await(make_unique_value()); + auto value = psco::sync_await(make_unique_value()); ASSERT_NE(value, nullptr); EXPECT_EQ(*value, 77); } TEST(UcoroTest, DeepRecursiveAwaitChainCompletes) { - ucoro::sync_await(recursive_task(10000)); + psco::sync_await(recursive_task(10000)); SUCCEED(); } TEST(UcoroTest, LazyAwaitableDestructorDoesNotStartCoroutine) { @@ -262,7 +244,7 @@ TEST(UcoroTest, ExplicitStartRunsOwnedCoroutine) { TEST(UcoroTest, StartDetachedRunsAsyncCoroutine) { Simulated_Async_Callbacks async; std::atomic flag{0}; - ucoro::start_detached(compute_callback_async_void(async, flag)); + compute_callback_async_void(async, flag).start_detached(); async.join_all(); EXPECT_EQ(flag.load(std::memory_order_acquire), 1); } @@ -276,7 +258,7 @@ TEST(UcoroTest, ExplicitStartDestroysSynchronouslyCompletedCoroutine) { TEST(UcoroTest, StartDetachedKeepsAsyncCoroutineAliveUntilCompletionThenDestroysIt) { Simulated_Async_Callbacks async; AllocationProbe::live_count().store(0, std::memory_order_release); - ucoro::start_detached(async_probe_task(async)); + async_probe_task(async).start_detached(); EXPECT_EQ(AllocationProbe::live_count().load(std::memory_order_acquire), 1); async.join_all(); EXPECT_EQ(AllocationProbe::live_count().load(std::memory_order_acquire), 0); @@ -285,7 +267,8 @@ TEST(UcoroTest, ResetStartedPendingTaskCancelsWithoutDestroyingFrameUntilCallbac Manual_Async_Callbacks async; std::atomic after_await{0}; AllocationProbe::live_count().store(0, std::memory_order_release); - auto task = ucoro::coro_start(manual_probe_task(async, after_await)); + auto task = manual_probe_task(async, after_await); + task.start(); ASSERT_TRUE(async.has_int_handler()); EXPECT_TRUE(task.valid()); EXPECT_EQ(AllocationProbe::live_count().load(std::memory_order_acquire), 1); @@ -304,8 +287,7 @@ TEST(UcoroTest, ResetStartedPendingTaskReportsOperationCancelledToCompletionHand std::condition_variable cv; bool completed = false; std::exception_ptr exception; - auto task = ucoro::coro_start(manual_probe_task(async, after_await), std::any{}, - [&](std::exception_ptr result) { + auto task = psco::with_callback(manual_probe_task(async, after_await), [&](std::exception_ptr result) { { std::lock_guard lock(mutex); exception = result; @@ -313,6 +295,7 @@ TEST(UcoroTest, ResetStartedPendingTaskReportsOperationCancelledToCompletionHand } cv.notify_one(); }); + task.start(); ASSERT_TRUE(async.has_int_handler()); task.reset(); async.complete_int(456); @@ -322,7 +305,7 @@ TEST(UcoroTest, ResetStartedPendingTaskReportsOperationCancelledToCompletionHand } EXPECT_EQ(after_await.load(std::memory_order_acquire), 0); ASSERT_TRUE(exception != nullptr); - EXPECT_THROW(std::rethrow_exception(exception), ucoro::operation_cancelled); + EXPECT_THROW(std::rethrow_exception(exception), psco::operation_cancelled); } TEST(UcoroTest, ConcurrentResetAndCallbackCompletionDoesNotCrash) { for (int i = 0; i < 100; ++i) { @@ -331,14 +314,14 @@ TEST(UcoroTest, ConcurrentResetAndCallbackCompletionDoesNotCrash) { std::mutex mutex; std::condition_variable cv; bool completed = false; - auto task = ucoro::coro_start(manual_probe_task(async, after_await), std::any{}, - [&](std::exception_ptr) { + auto task = psco::with_callback(manual_probe_task(async, after_await), [&](std::exception_ptr) { { std::lock_guard lock(mutex); completed = true; } cv.notify_one(); }); + task.start(); ASSERT_TRUE(async.has_int_handler()); std::thread reset_thread([&task] { task.reset(); @@ -362,8 +345,7 @@ TEST(UcoroTest, CancelStartedPendingTaskReportsOperationCancelledWithoutImmediat std::condition_variable cv; bool completed = false; std::exception_ptr exception; - auto task = ucoro::coro_start(manual_probe_task(async, after_await), std::any{}, - [&](std::exception_ptr result) { + auto task = psco::with_callback(manual_probe_task(async, after_await), [&](std::exception_ptr result) { { std::lock_guard lock(mutex); exception = result; @@ -371,6 +353,7 @@ TEST(UcoroTest, CancelStartedPendingTaskReportsOperationCancelledWithoutImmediat } cv.notify_one(); }); + task.start(); ASSERT_TRUE(async.has_int_handler()); EXPECT_TRUE(task.valid()); task.cancel(); @@ -382,14 +365,15 @@ TEST(UcoroTest, CancelStartedPendingTaskReportsOperationCancelledWithoutImmediat EXPECT_FALSE(task.valid()); EXPECT_EQ(after_await.load(std::memory_order_acquire), 0); ASSERT_TRUE(exception != nullptr); - EXPECT_THROW(std::rethrow_exception(exception), ucoro::operation_cancelled); + EXPECT_THROW(std::rethrow_exception(exception), psco::operation_cancelled); } TEST(UcoroTest, OwnedPendingTaskDestructorAbandonsAndDestroysAfterCallback) { Manual_Async_Callbacks async; std::atomic after_await{0}; AllocationProbe::live_count().store(0, std::memory_order_release); { - auto task = ucoro::coro_start(manual_probe_task(async, after_await)); + auto task = manual_probe_task(async, after_await); + task.start(); ASSERT_TRUE(async.has_int_handler()); EXPECT_TRUE(task.valid()); EXPECT_EQ(AllocationProbe::live_count().load(std::memory_order_acquire), 1); @@ -400,25 +384,24 @@ TEST(UcoroTest, OwnedPendingTaskDestructorAbandonsAndDestroysAfterCallback) { EXPECT_EQ(after_await.load(std::memory_order_acquire), 0); EXPECT_EQ(AllocationProbe::live_count().load(std::memory_order_acquire), 0); } -TEST(UcoroTest, MissingLocalStorageThrowsLogicError) { - EXPECT_THROW(static_cast(ucoro::sync_await(read_local_string())), std::logic_error); -} + TEST(UcoroTest, CompletionHandlerExceptionIsNotReportedByCallingHandlerTwice) { std::atomic calls{0}; - auto task = ucoro::coro_start(sync_probe_task(), std::any{}, - [&](std::exception_ptr) { + auto task = psco::with_callback(sync_probe_task(), [&](std::exception_ptr) { calls.fetch_add(1, std::memory_order_acq_rel); throw std::runtime_error("handler-error"); }); + task.start(); EXPECT_FALSE(task.valid()); EXPECT_EQ(calls.load(std::memory_order_acquire), 1); } namespace { - ucoro::awaitable callback_that_must_not_start_after_abandon(std::atomic& callback_started) { - co_await ucoro::callback_awaitable([&callback_started](auto handler) { + psco::awaitable callback_that_must_not_start_after_abandon(std::atomic& callback_started) { + co_await psco::callback_awaitable([&callback_started](auto handler) { callback_started.fetch_add(1, std::memory_order_acq_rel); handler(); }); + co_return; } } TEST(UcoroTest, AbandonedTaskDoesNotStartNewCallbackAwaiter) { @@ -436,21 +419,21 @@ namespace { constexpr bool await_suspend(std::coroutine_handle<>) const noexcept { return false; } constexpr int await_resume() const noexcept { return value; } }; - ucoro::awaitable await_plain_third_party_awaiter() { + psco::awaitable await_plain_third_party_awaiter() { auto value = co_await Immediate_Third_Party_Awaiter{41}; co_return value + 1; } struct External_Async_Operation { Manual_Async_Callbacks* async; }; - ucoro::awaitable external_operation_as_ucoro(External_Async_Operation op) { - auto value = co_await ucoro::callback_awaitable([op](auto handler) mutable { + psco::awaitable external_operation_as_ucoro(External_Async_Operation op) { + auto value = co_await psco::callback_awaitable([op](auto handler) mutable { op.async->async_int(std::move(handler)); }); co_return value; } } -namespace ucoro { +namespace psco { template <> struct await_transformer { static auto await_transform(External_Async_Operation op) { @@ -459,52 +442,53 @@ namespace ucoro { }; } namespace { - ucoro::awaitable await_external_operation(Manual_Async_Callbacks& async) { + psco::awaitable await_external_operation(Manual_Async_Callbacks& async) { auto value = co_await External_Async_Operation{&async}; co_return value + 1; } - ucoro::awaitable callback_registration_throws() { - auto value = co_await ucoro::callback_awaitable([](auto) { + psco::awaitable callback_registration_throws() { + auto value = co_await psco::callback_awaitable([](auto) { throw std::runtime_error("registration-error"); }); co_return value; } - ucoro::awaitable sequential_callbacks(Simulated_Async_Callbacks& async) { - auto first = co_await ucoro::callback_awaitable([&async](auto handler) { + psco::awaitable sequential_callbacks(Simulated_Async_Callbacks& async) { + auto first = co_await psco::callback_awaitable([&async](auto handler) { async.async_int(1, std::move(handler)); }); - auto second = co_await ucoro::callback_awaitable([&async](auto handler) { + auto second = co_await psco::callback_awaitable([&async](auto handler) { async.async_int(2, std::move(handler)); }); co_return first + second; } - ucoro::awaitable pending_child_callback( + psco::awaitable pending_child_callback( Manual_Async_Callbacks& async, std::atomic& child_after_await) { - auto value = co_await ucoro::callback_awaitable([&async](auto handler) { + auto value = co_await psco::callback_awaitable([&async](auto handler) { async.async_int(std::move(handler)); }); child_after_await.store(value, std::memory_order_release); + co_return; } - ucoro::awaitable parent_waiting_on_pending_child( + psco::awaitable parent_waiting_on_pending_child( Manual_Async_Callbacks& async, std::atomic& parent_after_child, std::atomic& child_after_await) { co_await pending_child_callback(async, child_after_await); parent_after_child.store(1, std::memory_order_release); + co_return; } } TEST(UcoroTest, AllowsPlainThirdPartyAwaiterThroughAwaitTransform) { - EXPECT_EQ(ucoro::sync_await(await_plain_third_party_awaiter()), 42); + EXPECT_EQ(psco::sync_await(await_plain_third_party_awaiter()), 42); } TEST(UcoroTest, AwaitTransformerAdaptsExternalOperation) { Manual_Async_Callbacks async; std::mutex mutex; std::condition_variable cv; bool completed = false; - ucoro::traits::exception_with_result_t result; - auto task = ucoro::coro_start(await_external_operation(async), std::any{}, - [&](ucoro::traits::exception_with_result_t r) mutable { + psco::traits::exception_with_result_t result; + auto task = psco::with_callback(await_external_operation(async), [&](psco::traits::exception_with_result_t r) mutable { { std::lock_guard lock(mutex); result = std::move(r); @@ -512,6 +496,7 @@ TEST(UcoroTest, AwaitTransformerAdaptsExternalOperation) { } cv.notify_one(); }); + task.start(); ASSERT_TRUE(async.has_int_handler()); async.complete_int(41); { @@ -523,11 +508,11 @@ TEST(UcoroTest, AwaitTransformerAdaptsExternalOperation) { EXPECT_EQ(std::get(result), 42); } TEST(UcoroTest, CallbackRegistrationExceptionPropagatesThroughSyncAwait) { - EXPECT_THROW(static_cast(ucoro::sync_await(callback_registration_throws())), std::runtime_error); + EXPECT_THROW(static_cast(psco::sync_await(callback_registration_throws())), std::runtime_error); } TEST(UcoroTest, SequentialCallbackAwaitersUseIndependentState) { Simulated_Async_Callbacks async; - EXPECT_EQ(ucoro::sync_await(sequential_callbacks(async)), 300); + EXPECT_EQ(psco::sync_await(sequential_callbacks(async)), 300); } TEST(UcoroTest, ResetParentPendingOnChildAbandonsChildAndSkipsContinuations) { Manual_Async_Callbacks async; @@ -537,9 +522,8 @@ TEST(UcoroTest, ResetParentPendingOnChildAbandonsChildAndSkipsContinuations) { std::condition_variable cv; bool completed = false; std::exception_ptr exception; - auto task = ucoro::coro_start( + auto task = psco::with_callback( parent_waiting_on_pending_child(async, parent_after_child, child_after_await), - std::any{}, [&](std::exception_ptr result) { { std::lock_guard lock(mutex); @@ -548,6 +532,7 @@ TEST(UcoroTest, ResetParentPendingOnChildAbandonsChildAndSkipsContinuations) { } cv.notify_one(); }); + task.start(); ASSERT_TRUE(async.has_int_handler()); task.reset(); async.complete_int(99); @@ -558,5 +543,5 @@ TEST(UcoroTest, ResetParentPendingOnChildAbandonsChildAndSkipsContinuations) { EXPECT_EQ(parent_after_child.load(std::memory_order_acquire), 0); EXPECT_EQ(child_after_await.load(std::memory_order_acquire), 0); ASSERT_TRUE(exception != nullptr); - EXPECT_THROW(std::rethrow_exception(exception), ucoro::operation_cancelled); + EXPECT_THROW(std::rethrow_exception(exception), psco::operation_cancelled); } diff --git a/Core/Serial/Serial_Coro.h b/Core/Serial/Serial_Coro.h index 2a8e44b..bdbc0cb 100644 --- a/Core/Serial/Serial_Coro.h +++ b/Core/Serial/Serial_Coro.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -53,13 +53,13 @@ public: io_context_.restart(); } - [[nodiscard]] ucoro::awaitable tick_coro() + [[nodiscard]] psco::awaitable tick_coro() { io_context_.poll(); co_return; } - [[nodiscard]] ucoro::awaitable read_coro(std::size_t max_size = 16 * 1024) + [[nodiscard]] psco::awaitable read_coro(std::size_t max_size = 16 * 1024) { co_await tick_coro(); if (!port_ || !port_->is_open()) { @@ -78,7 +78,7 @@ public: co_return data; } - [[nodiscard]] ucoro::awaitable write_coro(std::string data) + [[nodiscard]] psco::awaitable write_coro(std::string data) { co_await tick_coro(); if (!port_ || !port_->is_open() || data.empty()) { @@ -97,12 +97,12 @@ public: std::string read(int64_t size = -1) { auto max_size = size > 0 ? static_cast(size) : static_cast(16 * 1024); - return ucoro::sync_await(read_coro(max_size)); + return psco::sync_await(read_coro(max_size)); } int64_t write(const std::string& data) { - return static_cast(ucoro::sync_await(write_coro(data))); + return static_cast(psco::sync_await(write_coro(data))); } int get_available_bytes() diff --git a/Core/socket/Socket_Coro.h b/Core/socket/Socket_Coro.h index e68c504..c0c72e4 100644 --- a/Core/socket/Socket_Coro.h +++ b/Core/socket/Socket_Coro.h @@ -6,7 +6,7 @@ #include "UDP_Client.h" #include "UDP_Server.h" -#include +#include #include #include @@ -21,25 +21,25 @@ namespace Psc::asio_socket { class TCP_Client_Coro : public TCP_Client { public: - [[nodiscard]] ucoro::awaitable connect_coro() + [[nodiscard]] psco::awaitable connect_coro() { auto started = start_connect(); tick(); co_return started; } - [[nodiscard]] ucoro::awaitable tick_coro() + [[nodiscard]] psco::awaitable tick_coro() { tick(); co_return; } - [[nodiscard]] ucoro::awaitable read_coro() + [[nodiscard]] psco::awaitable read_coro() { co_return read(); } - [[nodiscard]] ucoro::awaitable send_coro(std::string data) + [[nodiscard]] psco::awaitable send_coro(std::string data) { send(data); co_return; @@ -48,40 +48,40 @@ public: class TCP_Server_Coro : public TCP_Server { public: - [[nodiscard]] ucoro::awaitable listen_coro(std::string ip, std::uint32_t port) + [[nodiscard]] psco::awaitable listen_coro(std::string ip, std::uint32_t port) { co_return listen(std::move(ip), port); } - [[nodiscard]] ucoro::awaitable listen_coro(Sockaddr_In address) + [[nodiscard]] psco::awaitable listen_coro(Sockaddr_In address) { co_return listen(address); } - [[nodiscard]] ucoro::awaitable tick_coro() + [[nodiscard]] psco::awaitable tick_coro() { tick(); co_return; } - [[nodiscard]] ucoro::awaitable flush_clients_coro() + [[nodiscard]] psco::awaitable flush_clients_coro() { flush_clients(); co_return; } - [[nodiscard]] ucoro::awaitable write_to_all_clients_coro(std::string data) + [[nodiscard]] psco::awaitable write_to_all_clients_coro(std::string data) { write_to_all_clients(data); co_return; } - [[nodiscard]] ucoro::awaitable> read_from_all_clients_coro() + [[nodiscard]] psco::awaitable> read_from_all_clients_coro() { co_return read_from_all_clients(); } - [[nodiscard]] ucoro::awaitable> accept_coro() const + [[nodiscard]] psco::awaitable> accept_coro() const { co_return accept(); } @@ -89,23 +89,23 @@ public: class UDP_Client_Coro : public UDP_Client { public: - [[nodiscard]] ucoro::awaitable connect_coro() + [[nodiscard]] psco::awaitable connect_coro() { co_return connect(); } - [[nodiscard]] ucoro::awaitable read_coro() + [[nodiscard]] psco::awaitable read_coro() { co_return read(); } - [[nodiscard]] ucoro::awaitable tick_coro() + [[nodiscard]] psco::awaitable tick_coro() { tick(); co_return; } - [[nodiscard]] ucoro::awaitable send_coro(std::string data) + [[nodiscard]] psco::awaitable send_coro(std::string data) { send(data); co_return; @@ -114,30 +114,30 @@ public: class UDP_Server_Coro : public UDP_Server { public: - [[nodiscard]] ucoro::awaitable tick_coro() + [[nodiscard]] psco::awaitable tick_coro() { tick(); co_return; } - [[nodiscard]] ucoro::awaitable> read_coro() + [[nodiscard]] psco::awaitable> read_coro() { co_return read(); } - [[nodiscard]] ucoro::awaitable reply_last_peer_coro(std::string data) + [[nodiscard]] psco::awaitable reply_last_peer_coro(std::string data) { reply_last_peer(data); co_return; } - [[nodiscard]] ucoro::awaitable send_to_coro(std::string ip, uint16_t port, std::string data) + [[nodiscard]] psco::awaitable send_to_coro(std::string ip, uint16_t port, std::string data) { send_to(ip, port, data); co_return; } - [[nodiscard]] ucoro::awaitable write_to_all_clients_coro(std::string msg) + [[nodiscard]] psco::awaitable write_to_all_clients_coro(std::string msg) { write_to_all_clients(msg); co_return; @@ -164,7 +164,7 @@ inline void throw_if_error(const asio::error_code& ec) } } -inline ucoro::awaitable +inline psco::awaitable tcp_resolve(asio::ip::tcp::resolver& resolver, std::string host, std::uint16_t port) @@ -174,7 +174,7 @@ tcp_resolve(asio::ip::tcp::resolver& resolver, asio::ip::tcp::resolver::results_type endpoints; }; - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&resolver, host = std::move(host), port](auto done) mutable { resolver.async_resolve( host, @@ -189,7 +189,7 @@ tcp_resolve(asio::ip::tcp::resolver& resolver, co_return std::move(result.endpoints); } -inline ucoro::awaitable +inline psco::awaitable tcp_connect(asio::ip::tcp::socket& socket, const asio::ip::tcp::resolver::results_type& endpoints) { @@ -198,7 +198,7 @@ tcp_connect(asio::ip::tcp::socket& socket, asio::ip::tcp::endpoint endpoint; }; - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&socket, &endpoints](auto done) mutable { asio::async_connect( socket, @@ -213,7 +213,7 @@ tcp_connect(asio::ip::tcp::socket& socket, co_return result.endpoint; } -inline ucoro::awaitable +inline psco::awaitable tcp_connect(asio::ip::tcp::socket& socket, asio::ip::tcp::resolver& resolver, std::string host, @@ -223,12 +223,12 @@ tcp_connect(asio::ip::tcp::socket& socket, co_return co_await tcp_connect(socket, endpoints); } -inline ucoro::awaitable> +inline psco::awaitable> tcp_accept(asio::ip::tcp::acceptor& acceptor) { auto socket = std::make_shared(acceptor.get_executor()); - auto ec = co_await ucoro::callback_awaitable( + auto ec = co_await psco::callback_awaitable( [&acceptor, socket](auto done) mutable { acceptor.async_accept( *socket, @@ -241,7 +241,7 @@ tcp_accept(asio::ip::tcp::acceptor& acceptor) co_return socket; } -inline ucoro::awaitable +inline psco::awaitable tcp_read_some(asio::ip::tcp::socket& socket, std::size_t max_size = 16 * 1024) { @@ -251,7 +251,7 @@ tcp_read_some(asio::ip::tcp::socket& socket, }; auto buffer = std::make_shared>(max_size); - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&socket, buffer](auto done) mutable { socket.async_read_some( asio::buffer(*buffer), @@ -266,7 +266,7 @@ tcp_read_some(asio::ip::tcp::socket& socket, co_return TCP_Read_Result{std::move(*buffer)}; } -inline ucoro::awaitable +inline psco::awaitable tcp_write(asio::ip::tcp::socket& socket, std::string data) { @@ -276,7 +276,7 @@ tcp_write(asio::ip::tcp::socket& socket, }; auto buffer = std::make_shared(std::move(data)); - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&socket, buffer](auto done) mutable { asio::async_write( socket, @@ -291,7 +291,7 @@ tcp_write(asio::ip::tcp::socket& socket, co_return result.size; } -inline ucoro::awaitable +inline psco::awaitable udp_receive_from(asio::ip::udp::socket& socket, std::size_t max_size = 16 * 1024) { @@ -303,7 +303,7 @@ udp_receive_from(asio::ip::udp::socket& socket, auto buffer = std::make_shared>(max_size); auto remote = std::make_shared(); - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&socket, buffer, remote](auto done) mutable { socket.async_receive_from( asio::buffer(*buffer), @@ -319,7 +319,7 @@ udp_receive_from(asio::ip::udp::socket& socket, co_return UDP_Read_Result{endpoint_to_sockaddr(result.remote), std::move(*buffer)}; } -inline ucoro::awaitable +inline psco::awaitable udp_send_to(asio::ip::udp::socket& socket, std::string data, asio::ip::udp::endpoint remote) @@ -330,7 +330,7 @@ udp_send_to(asio::ip::udp::socket& socket, }; auto buffer = std::make_shared(std::move(data)); - auto result = co_await ucoro::callback_awaitable( + auto result = co_await psco::callback_awaitable( [&socket, buffer, remote = std::move(remote)](auto done) mutable { socket.async_send_to( asio::buffer(*buffer), @@ -345,7 +345,7 @@ udp_send_to(asio::ip::udp::socket& socket, co_return result.size; } -inline ucoro::awaitable +inline psco::awaitable udp_send_to(asio::ip::udp::socket& socket, std::string data, const Sockaddr_In& remote) diff --git a/main.cmake b/main.cmake index 7e3a614..a5b8d07 100644 --- a/main.cmake +++ b/main.cmake @@ -190,10 +190,12 @@ if(1) target_compile_definitions(Core_Interface INTERFACE _USE_GTEST) target_link_libraries(Core_Static PUBLIC GTest::gtest GTest::gmock) target_sources(Core_Static PUBLIC ${ucoro_srcs}) + endif() -set(ucoro_dir "${CMAKE_CURRENT_LIST_DIR}/3rd/ucoro/src") +set(ucoro_dir "${CMAKE_CURRENT_LIST_DIR}/3rd/psco/src") file(GLOB_RECURSE ucoro_srcs ${ucoro_dir}/*.h ${ucoro_dir}/*.hpp ${ucoro_dir}/*.cpp) +target_include_directories(Core_Static PUBLIC ${CMAKE_CURRENT_LIST_DIR}/3rd/psco/include) target_sources(Core_Static PUBLIC ${ucoro_srcs}) target_link_libraries(Core_Static PUBLIC Core_Interface)