break out boost coroutines async_send

async_send is a method that was attempted to be shared between coroutine
and non-coroutine cases.  Unfortunately to have this code sharing
requires a very expensive template, boost::asio::initiate.  While this
template is great for generalizing, it results in a template
instantiation per call site, which doesn't scale well at build time in
things like bmcweb, where we have 400+ async_method_call sites.

This commit breaks out async_send into async_send and async_send_yield,
which allows using concrete callback and return types, thus avoiding
the multiple template instantiations.

Tested: ClangBuildAnalyzer shows that this template is no longer one of
the longest to instantiate.

Change-Id: Ic8f226e5be71f05c5f5dcb73eb51e6094dc704eb
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/example/asio-example.cpp b/example/asio-example.cpp
index 145e87a..f7f0522 100644
--- a/example/asio-example.cpp
+++ b/example/asio-example.cpp
@@ -108,7 +108,7 @@
     std::vector<uint8_t> commandData = {4, 3, 2, 1};
     method.append(netFn, lun, cmd, commandData, options);
     boost::system::error_code ec;
-    sdbusplus::message_t reply = conn->async_send(method, yield[ec]);
+    sdbusplus::message_t reply = conn->async_send_yield(method, yield[ec]);
     std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
         tupleOut;
     try
diff --git a/include/sdbusplus/asio/connection.hpp b/include/sdbusplus/asio/connection.hpp
index 9a75b5c..d48d721 100644
--- a/include/sdbusplus/asio/connection.hpp
+++ b/include/sdbusplus/asio/connection.hpp
@@ -82,21 +82,26 @@
      *  @param[in] timeout - The timeout in microseconds
      *
      */
-    template <typename CompletionToken>
-    inline auto async_send(message_t& m, CompletionToken&& token,
+
+    using callback_t = void(boost::system::error_code, message_t&);
+    using send_function = std::move_only_function<callback_t>;
+    inline void async_send(message_t& m, send_function&& callback,
                            uint64_t timeout = 0)
     {
-#ifdef SDBUSPLUS_DISABLE_BOOST_COROUTINES
-        constexpr bool is_yield = false;
-#else
-        constexpr bool is_yield =
-            std::is_same_v<CompletionToken, boost::asio::yield_context>;
-#endif
-        using return_t = std::conditional_t<is_yield, message_t, message_t&>;
-        using callback_t = void(boost::system::error_code, return_t);
-        return boost::asio::async_initiate<CompletionToken, callback_t>(
+        boost::asio::async_initiate<send_function, callback_t>(
+            detail::async_send_handler(get(), m, timeout), callback);
+    }
+#ifndef SDBUSPLUS_DISABLE_BOOST_COROUTINES
+    inline auto async_send_yield(message_t& m,
+                                 boost::asio::yield_context&& token,
+                                 uint64_t timeout = 0)
+    {
+        using yield_callback_t = void(boost::system::error_code, message_t);
+        return boost::asio::async_initiate<boost::asio::yield_context,
+                                           yield_callback_t>(
             detail::async_send_handler(get(), m, timeout), token);
     }
+#endif
 
     /** @brief Perform an asynchronous method call, with input parameter packing
      *         and return value unpacking.
@@ -270,7 +275,7 @@
         if (!ec)
         {
             message_t r;
-            r = async_send(m, yield[ec]);
+            r = async_send_yield(m, yield[ec]);
             try
             {
                 return r.unpack<RetTypes...>();