Files
LuaVox/Src/TOSAsync.hpp
2025-03-11 19:37:36 +06:00

179 lines
5.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 <boost/asio.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <exception>
#include <memory>
#include <type_traits>
namespace TOS {
using namespace boost::asio::experimental::awaitable_operators;
namespace asio = boost::asio;
template<typename T = void>
using coro = boost::asio::awaitable<T>;
// class AsyncSemaphore
// {
// boost::asio::deadline_timer Deadline;
// std::atomic<uint8_t> 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<bool()> 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<MultipleToOne_AsyncSymaphore> Symaphore;
std::exception_ptr LastException;
public:
WaitableCoro(asio::io_context &ioc)
: IOC(ioc)
{}
template<typename Token>
void co_spawn(Token token) {
Symaphore = std::make_shared<MultipleToOne_AsyncSymaphore>(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<IAsyncDestructible> {
protected:
asio::io_context &IOC;
virtual coro<> asyncDestructor() { co_return; }
public:
IAsyncDestructible(asio::io_context &ioc)
: IOC(ioc)
{}
virtual ~IAsyncDestructible() {}
protected:
template<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
static std::shared_ptr<T> createShared(asio::io_context &ioc, T *ptr)
{
return std::shared_ptr<T>(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<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
static coro<std::shared_ptr<T>> createShared(T *ptr)
{
co_return std::shared_ptr<T>(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<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
static std::unique_ptr<T, std::function<void(T*)>> createUnique(asio::io_context &ioc, T *ptr)
{
return std::unique_ptr<T, std::function<void(T*)>>(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<typename T, typename = typename std::is_same<IAsyncDestructible, T>>
static coro<std::unique_ptr<T, std::function<void(T*)>>> createUnique(T *ptr)
{
co_return std::unique_ptr<T, std::function<void(T*)>>(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);
});
}
};
}