#pragma once #include "TOSLib.hpp" #include "boost/asio/associated_cancellation_slot.hpp" #include "boost/asio/associated_executor.hpp" #include "boost/asio/deadline_timer.hpp" #include "boost/asio/io_context.hpp" #include "boost/system/detail/error_code.hpp" #include #include #include #include #include #include namespace TOS { using namespace boost::asio::experimental::awaitable_operators; namespace asio = boost::asio; template using coro = boost::asio::awaitable; // class AsyncSemaphore // { // boost::asio::deadline_timer Deadline; // std::atomic Lock = 0; // public: // AsyncSemaphore(boost::asio::io_context& ioc) // : Deadline(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin)) // {} // coro<> async_wait() { // try { // co_await Deadline.async_wait(boost::asio::use_awaitable); // } catch(boost::system::system_error code) { // if(code.code() != boost::system::errc::operation_canceled) // throw; // } // co_await asio::this_coro::throw_if_cancelled(); // } // coro<> async_wait(std::function predicate) { // while(!predicate()) // co_await async_wait(); // } // void notify_one() { // Deadline.cancel_one(); // } // void notify_all() { // Deadline.cancel(); // } // }; /* Многие могут уведомлять одного Ждёт события. После доставки уведомления ждёт повторно */ class MultipleToOne_AsyncSymaphore { asio::deadline_timer Timer; public: MultipleToOne_AsyncSymaphore(asio::io_context &ioc) : Timer(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin)) {} void notify() { Timer.cancel(); } void wait() { Timer.wait(); Timer.expires_at(boost::posix_time::ptime(boost::posix_time::pos_infin)); } coro<> async_wait() { try { co_await Timer.async_wait(); } catch(...) {} } }; class WaitableCoro { asio::io_context &IOC; std::shared_ptr Symaphore; std::exception_ptr LastException; public: WaitableCoro(asio::io_context &ioc) : IOC(ioc) {} template void co_spawn(Token token) { Symaphore = std::make_shared(IOC); asio::co_spawn(IOC, [token = std::move(token), symaphore = Symaphore]() -> coro<> { co_await std::move(token); symaphore->notify(); }, asio::detached); } void wait() { Symaphore->wait(); } coro<> async_wait() { return Symaphore->async_wait(); } }; /* Используется, чтобы вместо уничтожения объекта в умной ссылке, вызвать корутину с co_await asyncDestructor() */ class IAsyncDestructible : public std::enable_shared_from_this { protected: asio::io_context &IOC; virtual coro<> asyncDestructor() { co_return; } public: IAsyncDestructible(asio::io_context &ioc) : IOC(ioc) {} virtual ~IAsyncDestructible() {} protected: template> static std::shared_ptr createShared(asio::io_context &ioc, T *ptr) { return std::shared_ptr(ptr, [&ioc = ioc](T *ptr) { boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { try { co_await ptr->asyncDestructor(); } catch(...) { } delete ptr; co_return; } (ptr), boost::asio::detached); }); } template> static coro> createShared(T *ptr) { co_return std::shared_ptr(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) { boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { try { co_await ptr->asyncDestructor(); } catch(...) { } delete ptr; co_return; } (ptr), boost::asio::detached); }); } template> static std::unique_ptr> createUnique(asio::io_context &ioc, T *ptr) { return std::unique_ptr>(ptr, [&ioc = ioc](T *ptr) { boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { try { co_await ptr->asyncDestructor(); } catch(...) { } delete ptr; co_return; } (ptr), boost::asio::detached); }); } template> static coro>> createUnique(T *ptr) { co_return std::unique_ptr>(ptr, [ioc = asio::get_associated_executor(co_await asio::this_coro::executor)](T *ptr) { boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { try { co_await ptr->asyncDestructor(); } catch(...) { } delete ptr; co_return; } (ptr), boost::asio::detached); }); } }; }