LCOV - code coverage report
Current view: top level - capy/asio - executor_from_asio.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 94.1 % 34 32 2
Test Date: 2026-05-01 02:54:45 Functions: 90.9 % 11 10 1

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/cppalliance/capy
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_CAPY_ASIO_EXECUTOR_FROM_ASIO_HPP
      11                 : #define BOOST_CAPY_ASIO_EXECUTOR_FROM_ASIO_HPP
      12                 : 
      13                 : #include <boost/capy/asio/detail/asio_context_service.hpp>
      14                 : #include <boost/capy/asio/detail/asio_coroutine_unique_handle.hpp>
      15                 : #include <boost/capy/asio/detail/fwd.hpp>
      16                 : #include <boost/capy/ex/frame_allocator.hpp>
      17                 : 
      18                 : 
      19                 : #include <memory_resource>
      20                 : #include <type_traits>
      21                 : 
      22                 : namespace boost {
      23                 : namespace capy {
      24                 : 
      25                 : /** @addtogroup asio
      26                 :  *  @{
      27                 :  */
      28                 : 
      29                 : namespace detail
      30                 : {
      31                 : 
      32                 : /** @brief Concept for legacy Networking TS style Asio executors.
      33                 :  *  @internal
      34                 :  *
      35                 :  *  Matches executors that provide the original Networking TS executor interface
      36                 :  *  with explicit work counting (`on_work_started`/`on_work_finished`) and
      37                 :  *  `dispatch`/`post` methods that take a handler and allocator.
      38                 :  *
      39                 :  *  @tparam Executor The type to check
      40                 :  */
      41                 : template<typename Executor>
      42                 : concept AsioNetTsExecutor =  requires (Executor exec,
      43                 :                      std::coroutine_handle<> h,
      44                 :                      std::pmr::polymorphic_allocator<void> a)
      45                 :     {
      46                 :       exec.on_work_started();
      47                 :       exec.on_work_finished();
      48                 :       exec.dispatch(h, a);
      49                 :       exec.post(h, a);
      50                 :       exec.context();
      51                 :     } ;
      52                 : 
      53                 : /** @brief Concept for Boost.Asio standard executors.
      54                 :  *  @internal
      55                 :  *
      56                 :  *  Matches executors compatible with the P0443/P2300 executor model as
      57                 :  *  implemented in Boost.Asio. These executors use the property query/require
      58                 :  *  mechanism and return `boost::asio::execution_context&` from context queries.
      59                 :  *
      60                 :  *  @tparam Executor The type to check
      61                 :  */
      62                 : template<typename Executor>
      63                 : concept AsioBoostStandardExecutor = std::same_as<
      64                 :       typename boost::asio::query_result<
      65                 :         Executor,
      66                 :         boost::asio::execution::detail::context_t<0>>::type,
      67                 :         boost::asio::execution_context&>;
      68                 : 
      69                 : /** @brief Concept for standalone Asio standard executors.
      70                 :  *  @internal
      71                 :  *
      72                 :  *  Matches executors compatible with the P0443/P2300 executor model as
      73                 :  *  implemented in standalone Asio. These executors return
      74                 :  *  `::asio::execution_context&` from context queries.
      75                 :  *
      76                 :  *  @tparam Executor The type to check
      77                 :  */
      78                 : template<typename Executor>
      79                 : concept AsioStandaloneStandardExecutor = std::same_as<
      80                 :       typename ::asio::query_result<
      81                 :         Executor,
      82                 :         ::asio::execution::detail::context_t<0>>::type,
      83                 :         ::asio::execution_context&>;
      84                 : 
      85                 : }
      86                 : 
      87                 : 
      88                 : /** @brief Wraps a legacy Networking TS executor for use with capy.
      89                 :  *
      90                 :  *  This class adapts Asio executors that follow the original Networking TS
      91                 :  *  executor model (with `on_work_started`/`on_work_finished` and
      92                 :  *  `dispatch`/`post` methods) to be usable as capy executors.
      93                 :  *
      94                 :  *  @tparam Executor An executor type satisfying `AsioNetTsExecutor`
      95                 :  *
      96                 :  *  @par Example
      97                 :  *  @code
      98                 :  *  boost::asio::io_context io;
      99                 :  *  auto wrapped = asio_net_ts_executor(io.get_executor());
     100                 :  *
     101                 :  *  // Use with capy coroutines
     102                 :  *  capy::run(wrapped, my_coroutine());
     103                 :  *  @endcode
     104                 :  *
     105                 :  *  @see wrap_asio_executor For automatic executor type detection
     106                 :  */
     107                 : template<detail::AsioNetTsExecutor Executor>
     108                 : struct asio_net_ts_executor
     109                 : {
     110                 :   /** @brief Constructs from an Asio Net.TS executor.
     111                 :    *  @param executor The Asio executor to wrap
     112                 :    */
     113 HIT           2 :   asio_net_ts_executor(Executor executor)
     114                 :       noexcept(std::is_nothrow_move_constructible_v<Executor>)
     115               2 :       : executor_(std::move(executor))
     116                 :   {
     117               2 :   }
     118                 : 
     119                 :   /** @brief Move constructor. */
     120              10 :   asio_net_ts_executor(asio_net_ts_executor && rhs)
     121                 :       noexcept(std::is_nothrow_move_constructible_v<Executor>)
     122              10 :       : executor_(std::move(rhs.executor_))
     123                 :   {
     124              10 :   }
     125                 : 
     126                 :   /** @brief Copy constructor. */
     127               1 :   asio_net_ts_executor(const asio_net_ts_executor & rhs)
     128                 :       noexcept(std::is_nothrow_copy_constructible_v<Executor>)
     129               1 :       : executor_(rhs.executor_)
     130                 :   {
     131               1 :   }
     132                 : 
     133                 :   /** @brief Returns the associated capy execution context.
     134                 :    *
     135                 :    *  The context is obtained via an `asio_context_service` registered
     136                 :    *  with the underlying Asio execution context.
     137                 :    *
     138                 :    *  @return Reference to the capy execution_context
     139                 :    */
     140               6 :   execution_context& context() const noexcept
     141                 :   {
     142                 :       using ex_t = std::remove_reference_t<decltype(executor_.context())>;
     143                 :       return use_service<detail::asio_context_service<ex_t>>
     144               6 :             (
     145                 :               executor_.context()
     146               6 :             );
     147                 :   }
     148                 : 
     149                 :   /** @brief Notifies that work has started.
     150                 :    *
     151                 :    *  Forwards to the underlying executor's `on_work_started()`.
     152                 :    */
     153              10 :   void on_work_started() const noexcept
     154                 :   {
     155              10 :     executor_.on_work_started();
     156              10 :   }
     157                 : 
     158                 :   /** @brief Notifies that work has finished.
     159                 :    *
     160                 :    *  Forwards to the underlying executor's `on_work_finished()`.
     161                 :    */
     162              12 :   void on_work_finished() const noexcept
     163                 :   {
     164              12 :     executor_.on_work_finished();
     165              12 :   }
     166                 : 
     167                 :   /** @brief Dispatches a continuation for execution.
     168                 :    *
     169                 :    *  May execute inline if allowed by the executor, otherwise posts.
     170                 :    *
     171                 :    *  @param c The continuation to dispatch
     172                 :    *  @return A noop coroutine handle (execution is delegated to Asio)
     173                 :    */
     174               5 :   std::coroutine_handle<> dispatch(continuation & c) const
     175                 :   {
     176               5 :     executor_.dispatch(
     177              10 :       detail::asio_coroutine_unique_handle(c.h),
     178               5 :       std::pmr::polymorphic_allocator<void>(
     179                 :         boost::capy::get_current_frame_allocator()));
     180                 : 
     181               5 :     return std::noop_coroutine();
     182                 :   }
     183                 : 
     184                 :   /** @brief Posts a continuation for deferred execution.
     185                 :    *
     186                 :    *  The continuation will never be executed inline.
     187                 :    *
     188                 :    *  @param c The continuation to post
     189                 :    */
     190               2 :   void post(continuation & c) const
     191                 :   {
     192               2 :     executor_.post(
     193               4 :       detail::asio_coroutine_unique_handle(c.h),
     194               2 :       std::pmr::polymorphic_allocator<void>(
     195                 :         boost::capy::get_current_frame_allocator()));
     196               2 :   }
     197                 : 
     198                 :   /** @brief Equality comparison. */
     199 MIS           0 :   bool operator==(const asio_net_ts_executor & rhs) const noexcept
     200                 :   {
     201               0 :     return executor_  == rhs.executor_;
     202                 :   }
     203                 : 
     204                 :   /** @brief Inequality comparison. */
     205                 :   bool operator!=(const asio_net_ts_executor & rhs) const noexcept
     206                 :   {
     207                 :     return executor_  != rhs.executor_;
     208                 :   }
     209                 : 
     210                 :  private:
     211                 :   Executor executor_;
     212                 : };
     213                 : 
     214                 : 
     215                 : /** @brief Wraps a Boost.Asio standard executor for use with capy.
     216                 :  *
     217                 :  *  Forward declaration; defined in `boost.hpp`.
     218                 :  *
     219                 :  *  @tparam Executor An executor type satisfying `AsioBoostStandardExecutor`
     220                 :  *  @see asio_net_ts_executor For legacy executor wrapping
     221                 :  */
     222                 : template<detail::AsioBoostStandardExecutor Executor>
     223                 : struct asio_boost_standard_executor;
     224                 : 
     225                 : /** @brief Wraps a standalone Asio standard executor for use with capy.
     226                 :  *
     227                 :  *  Forward declaration; defined in `standalone.hpp`.
     228                 :  *
     229                 :  *  @tparam Executor An executor type satisfying `AsioStandaloneStandardExecutor`
     230                 :  *  @see asio_net_ts_executor For legacy executor wrapping
     231                 :  */
     232                 : template<detail::AsioStandaloneStandardExecutor Executor>
     233                 : struct asio_standalone_standard_executor;
     234                 : 
     235                 : 
     236                 : /** @brief Automatically wraps any Asio executor for use with capy.
     237                 :  *
     238                 :  *  This function detects the type of Asio executor and returns the appropriate
     239                 :  *  capy-compatible wrapper:
     240                 :  *  - Legacy Net.TS executors -> `asio_net_ts_executor`
     241                 :  *  - Boost.Asio standard executors -> `asio_boost_standard_executor`
     242                 :  *  - Standalone Asio standard executors -> `asio_standalone_standard_executor`
     243                 :  *
     244                 :  *  @tparam Executor The Asio executor type (deduced)
     245                 :  *  @param exec The Asio executor to wrap
     246                 :  *  @return A capy-compatible executor wrapping the input
     247                 :  *
     248                 :  *  @par Example
     249                 :  *  @code
     250                 :  *  boost::asio::io_context io;
     251                 :  *  auto capy_exec = wrap_asio_executor(io.get_executor());
     252                 :  *
     253                 :  *  // Now use with capy
     254                 :  *  capy::run(capy_exec, my_io_task());
     255                 :  *  @endcode
     256                 :  *
     257                 :  *  @note Fails to compile with a static_assert if the executor type is not recognized.
     258                 :  */
     259                 : template<typename Executor>
     260 HIT           3 : auto wrap_asio_executor(Executor && exec)
     261                 : {
     262                 :   using executor_t = std::decay_t<Executor>;
     263                 :   if constexpr (detail::AsioNetTsExecutor<executor_t>)
     264                 :     return asio_net_ts_executor<executor_t>(
     265                 :               std::forward<Executor>(exec)
     266               2 :             );
     267                 :   else if constexpr (detail::AsioBoostStandardExecutor<executor_t>)
     268                 :     return asio_boost_standard_executor<executor_t>(
     269               1 :               std::forward<Executor>(exec)
     270               1 :             );
     271                 :   else if constexpr (detail::AsioStandaloneStandardExecutor<executor_t>)
     272                 :     return asio_standalone_standard_executor<executor_t>(
     273                 :               std::forward<Executor>(exec)
     274                 :             );
     275                 :   else
     276                 :     static_assert(sizeof(Executor) == 0, "Unknown executor type");
     277                 : };
     278                 : 
     279                 : 
     280                 : /** @brief Type alias for the result of `wrap_asio_executor`.
     281                 :  *
     282                 :  *  Given an Asio executor type, this alias yields the corresponding
     283                 :  *  capy wrapper type.
     284                 :  *
     285                 :  *  @tparam Executor The Asio executor type
     286                 :  */
     287                 : template<typename Executor>
     288                 : using wrap_asio_executor_t
     289                 :         = decltype(wrap_asio_executor(std::declval<const Executor &>()));
     290                 : 
     291                 : /** @} */ // end of asio group
     292                 : 
     293                 : 
     294                 : 
     295                 : }
     296                 : }
     297                 : 
     298                 : 
     299                 : #endif //BOOST_CAPY_ASIO_EXECUTOR_ADAPTER_HPP
        

Generated by: LCOV version 2.3