LCOV - code coverage report
Current view: top level - util - types.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 7 7
Test Date: 2026-11-10 10:38:07 Functions: 96.3 % 378 364

            Line data    Source code
       1              : #ifndef THINGER_TYPES
       2              : #define THINGER_TYPES
       3              : 
       4              : #include <concepts>
       5              : #include <functional>
       6              : #include <memory>
       7              : #include <type_traits>
       8              : #include <boost/asio.hpp>
       9              : #include <boost/asio/awaitable.hpp>
      10              : #include <boost/asio/use_awaitable.hpp>
      11              : #include <boost/asio/as_tuple.hpp>
      12              : #include <boost/asio/co_spawn.hpp>
      13              : #include <boost/asio/detached.hpp>
      14              : #include <boost/asio/experimental/awaitable_operators.hpp>
      15              : 
      16              : namespace thinger {
      17              : 
      18              :     // Awaitable type alias
      19              :     template<typename T = void>
      20              :     using awaitable = boost::asio::awaitable<T>;
      21              : 
      22              :     // Import commonly used awaitable utilities
      23              :     using boost::asio::use_awaitable;
      24              :     using boost::asio::co_spawn;
      25              :     using boost::asio::detached;
      26              : 
      27              :     // For error handling without exceptions (returns tuple<error_code, result>)
      28              :     constexpr auto use_nothrow_awaitable =
      29              :         boost::asio::as_tuple(boost::asio::use_awaitable);
      30              : 
      31              :     // Result type for socket read/write operations (error_code + bytes transferred)
      32              :     using io_result = std::tuple<boost::system::error_code, size_t>;
      33              : 
      34              :     // Awaitable operators for combining coroutines (||, &&)
      35              :     using namespace boost::asio::experimental::awaitable_operators;
      36              : 
      37              :     // Whether T is what a coroutine returns
      38              :     template<typename T>
      39              :     inline constexpr bool is_awaitable_v = false;
      40              : 
      41              :     template<typename T, typename Executor>
      42              :     inline constexpr bool is_awaitable_v<boost::asio::awaitable<T, Executor>> = true;
      43              : 
      44              :     // A callable that is not a coroutine when called with Args. A std::function<void(...)>
      45              :     // takes any callable, coroutines too: it would call a coroutine lambda only to drop the
      46              :     // awaitable it returns, so the coroutine would never run
      47              :     template<typename F, typename... Args>
      48              :     concept not_a_coroutine = !is_awaitable_v<std::invoke_result_t<F&, Args...>>;
      49              : 
      50              :     // A coroutine taking Args (returning awaitable<void>)
      51              :     template<typename F, typename... Args>
      52              :     concept coroutine_callable = std::same_as<std::invoke_result_t<F&, Args...>, awaitable<void>>;
      53              : 
      54              :     // Call a callback that may be a coroutine, awaiting it if it is
      55              :     template<typename F, typename... Args>
      56              :     awaitable<void> call_and_await(F& callback, Args&&... args) {
      57              :         if constexpr (is_awaitable_v<std::invoke_result_t<F&, Args...>>) {
      58              :             co_await std::invoke(callback, std::forward<Args>(args)...);
      59              :         } else {
      60              :             std::invoke(callback, std::forward<Args>(args)...);
      61              :         }
      62              :     }
      63              : 
      64              :     // `operation`, keeping `keeper` alive until it ends
      65              :     template<typename T>
      66         2442 :     awaitable<T> kept_alive(std::shared_ptr<void> keeper, awaitable<T> operation) {
      67              :         co_return co_await std::move(operation);
      68         4884 :     }
      69              : 
      70              :     // Run `operation` on `executor` (e.g. the strand of the object it uses), resuming the
      71              :     // caller where it was: at once if the caller already runs there. The operation keeps
      72              :     // `keeper` (the object it uses) alive, also if the caller goes away
      73              :     template<typename T>
      74        17574 :     awaitable<T> on_executor(boost::asio::any_io_executor executor, std::shared_ptr<void> keeper,
      75              :                              awaitable<T> operation) {
      76              :         if (executor == co_await boost::asio::this_coro::executor) co_return co_await std::move(operation);
      77              :         co_return co_await co_spawn(executor, kept_alive(std::move(keeper), std::move(operation)), use_awaitable);
      78        35148 :     }
      79              : 
      80              :     // A std::function for callbacks that are called, never awaited: it does not take a
      81              :     // coroutine (see not_a_coroutine), which then fails to compile instead of never running
      82              :     template<typename Signature>
      83              :     class sync_callback;
      84              : 
      85              :     template<typename R, typename... Args>
      86              :     class sync_callback<R(Args...)> : public std::function<R(Args...)> {
      87              :     public:
      88       114318 :         sync_callback() noexcept = default;
      89       118615 :         sync_callback(std::nullptr_t) noexcept {}
      90              : 
      91              :         template<typename F>
      92              :             requires (!std::same_as<std::remove_cvref_t<F>, sync_callback>) &&
      93              :                      std::constructible_from<std::function<R(Args...)>, F> &&
      94              :                      not_a_coroutine<std::remove_cvref_t<F>, Args...>
      95      2619105 :         sync_callback(F&& callback) : std::function<R(Args...)>(std::forward<F>(callback)) {}
      96              :     };
      97              : 
      98              : }
      99              : 
     100              : #endif
        

Generated by: LCOV version 2.0-1