async: remove tag_invoke calls

P2300R9 removed usage of tag_invoke.  stdexec still has it
but in order to be forward compliant with the C++26 standard
we should modernize the code and remove its usage.  This also
has the benefit of simplifying most sender/receiver implementations.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Ib0a1d0a82485c8d247a18daa020d0bba2249e95c
diff --git a/include/sdbusplus/async/callback.hpp b/include/sdbusplus/async/callback.hpp
index 0cdf6a1..10db758 100644
--- a/include/sdbusplus/async/callback.hpp
+++ b/include/sdbusplus/async/callback.hpp
@@ -100,12 +100,11 @@
     }
 
     // Call the init function upon Sender start.
-    friend void tag_invoke(execution::start_t,
-                           callback_operation& self) noexcept
+    void start() noexcept
     {
         try
         {
-            auto rc = self.init(handler, &self);
+            auto rc = init(handler, this);
             if (rc < 0)
             {
                 throw exception::SdBusError(-rc, __PRETTY_FUNCTION__);
@@ -113,8 +112,7 @@
         }
         catch (...)
         {
-            execution::set_error(std::move(self.receiver),
-                                 std::current_exception());
+            execution::set_error(std::move(receiver), std::current_exception());
         }
     }
 
@@ -132,21 +130,20 @@
 template <takes_msg_handler Init>
 struct callback_sender
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     explicit callback_sender(Init init) : init(std::move(init)) {};
 
     // This Sender yields a message_t.
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const callback_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<execution::set_value_t(message_t),
                                             execution::set_stopped_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, callback_sender&& self, R r)
-        -> callback_operation<Init, R>
+    auto connect(R r) -> callback_operation<Init, R>
     {
-        return {std::move(self.init), std::move(r)};
+        return {std::move(init), std::move(r)};
     }
 
   private:
diff --git a/include/sdbusplus/async/fdio.hpp b/include/sdbusplus/async/fdio.hpp
index abf3b42..de98cad 100644
--- a/include/sdbusplus/async/fdio.hpp
+++ b/include/sdbusplus/async/fdio.hpp
@@ -70,16 +70,12 @@
 
     friend fdio;
 
-    friend void tag_invoke(execution::start_t, fdio_completion& self) noexcept
-    {
-        self.arm();
-    }
+    void start() noexcept;
 
   private:
     virtual void complete() noexcept = 0;
     virtual void error(std::exception_ptr exceptionPtr) noexcept = 0;
     virtual void stop() noexcept = 0;
-    void arm() noexcept;
 
     fdio& fdioInstance;
     event_source_t source;
@@ -115,24 +111,23 @@
 // fdio Sender implementation.
 struct fdio_sender
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     fdio_sender() = delete;
     explicit fdio_sender(fdio& fdioInstance) noexcept :
         fdioInstance(fdioInstance) {};
 
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const fdio_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<
             execution::set_value_t(),
             execution::set_error_t(std::exception_ptr),
             execution::set_stopped_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, fdio_sender&& self, R r)
-        -> fdio_operation<R>
+    auto connect(R r) -> fdio_operation<R>
     {
-        return {self.fdioInstance, std::move(r)};
+        return {fdioInstance, std::move(r)};
     }
 
   private:
diff --git a/include/sdbusplus/async/match.hpp b/include/sdbusplus/async/match.hpp
index 4dbc61a..86a0dbc 100644
--- a/include/sdbusplus/async/match.hpp
+++ b/include/sdbusplus/async/match.hpp
@@ -86,15 +86,11 @@
 
     friend match;
 
-    friend void tag_invoke(execution::start_t, match_completion& self) noexcept
-    {
-        self.arm();
-    }
+    void start() noexcept;
 
   private:
     virtual void complete(message_t&&) noexcept = 0;
     virtual void stop() noexcept = 0;
-    void arm() noexcept;
 
     match& m;
 };
@@ -124,21 +120,20 @@
 // match Sender implementation.
 struct match_sender
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     match_sender() = delete;
     explicit match_sender(match& m) noexcept : m(m) {};
 
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const match_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<execution::set_value_t(message_t),
                                             execution::set_stopped_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, match_sender&& self, R r)
-        -> match_operation<R>
+    auto connect(R r) -> match_operation<R>
     {
-        return {self.m, std::move(r)};
+        return {m, std::move(r)};
     }
 
   private:
diff --git a/include/sdbusplus/async/mutex.hpp b/include/sdbusplus/async/mutex.hpp
index d937f92..db13882 100644
--- a/include/sdbusplus/async/mutex.hpp
+++ b/include/sdbusplus/async/mutex.hpp
@@ -85,15 +85,11 @@
 
     friend mutex;
 
-    friend void tag_invoke(execution::start_t, mutex_completion& self) noexcept
-    {
-        self.arm();
-    }
+    void start() noexcept;
 
   private:
     virtual void complete() noexcept = 0;
     virtual void stop() noexcept = 0;
-    void arm() noexcept;
 
     mutex& mutexInstance;
 };
@@ -123,22 +119,21 @@
 // mutex sender
 struct mutex_sender
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     mutex_sender() = delete;
     explicit mutex_sender(mutex& mutexInstance) noexcept :
         mutexInstance(mutexInstance) {};
 
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const mutex_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<execution::set_value_t(),
                                             execution::set_stopped_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, mutex_sender&& self, R r)
-        -> mutex_operation<R>
+    auto connect(R r) -> mutex_operation<R>
     {
-        return {self.mutexInstance, std::move(r)};
+        return {mutexInstance, std::move(r)};
     }
 
   private:
diff --git a/include/sdbusplus/async/timer.hpp b/include/sdbusplus/async/timer.hpp
index 582d248..808c8fe 100644
--- a/include/sdbusplus/async/timer.hpp
+++ b/include/sdbusplus/async/timer.hpp
@@ -46,17 +46,15 @@
         return 0;
     }
 
-    friend auto tag_invoke(execution::start_t, sleep_operation& self) noexcept
+    void start() noexcept
     {
         try
         {
-            self.source =
-                self.event_loop().add_oneshot_timer(handler, &self, self.time);
+            source = event_loop().add_oneshot_timer(handler, this, time);
         }
         catch (...)
         {
-            execution::set_error(std::move(self.receiver),
-                                 std::current_exception());
+            execution::set_error(std::move(receiver), std::current_exception());
         }
     }
 
@@ -77,7 +75,7 @@
  */
 struct sleep_sender : public context_ref, details::context_friend
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     sleep_sender() = delete;
 
@@ -85,18 +83,17 @@
         context_ref(ctx), time(time)
     {}
 
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const sleep_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<
             execution::set_value_t(),
             execution::set_error_t(std::exception_ptr),
             execution::set_stopped_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, sleep_sender&& self, R r)
-        -> sleep_operation<R>
+    auto connect(R r) -> sleep_operation<R>
     {
-        return {self.ctx, self.time, std::move(r)};
+        return {ctx, time, std::move(r)};
     }
 
     static auto sleep_for(context& ctx, event_t::time_resolution time)
diff --git a/src/async/context.cpp b/src/async/context.cpp
index d4ec5e9..0b31391 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -34,8 +34,7 @@
     // Called by the `caller` to indicate the Sender should be stopped.
     virtual void stop() noexcept = 0;
 
-    // Arm the completion event.
-    void arm() noexcept;
+    void start() noexcept;
 
     // Data to share with the worker.
     event_t::time_resolution timeout{};
@@ -70,32 +69,25 @@
         execution::set_value(std::move(this->receiver));
     }
 
-    friend void tag_invoke(execution::start_t,
-                           wait_process_operation& self) noexcept
-    {
-        self.arm();
-    }
-
     R receiver;
 };
 
 /* The sender for the wait/process event. */
 struct wait_process_sender : public context_ref
 {
-    using is_sender = void;
+    using sender_concept = execution::sender_t;
 
     explicit wait_process_sender(context& ctx) : context_ref(ctx) {}
 
-    friend auto tag_invoke(execution::get_completion_signatures_t,
-                           const wait_process_sender&, auto)
+    template <typename Self, class... Env>
+    static constexpr auto get_completion_signatures(Self&&, Env&&...)
         -> execution::completion_signatures<execution::set_value_t()>;
 
     template <execution::receiver R>
-    friend auto tag_invoke(execution::connect_t, wait_process_sender&& self,
-                           R r) -> wait_process_operation<R>
+    auto connect(R r) -> wait_process_operation<R>
     {
         // Create the completion for the wait.
-        return {self.ctx, std::move(r)};
+        return {ctx, std::move(r)};
     }
 };
 
@@ -282,7 +274,7 @@
     }
 }
 
-void details::wait_process_completion::arm() noexcept
+void details::wait_process_completion::start() noexcept
 {
     // Call process.  True indicates something was handled and we do not
     // need to `wait`, because there might be yet another pending operation
diff --git a/src/async/fdio.cpp b/src/async/fdio.cpp
index 94c79d1..df54cf0 100644
--- a/src/async/fdio.cpp
+++ b/src/async/fdio.cpp
@@ -59,7 +59,7 @@
     }
 }
 
-void fdio_completion::arm() noexcept
+void fdio_completion::start() noexcept
 {
     // Set ourselves as the awaiting Receiver
     std::unique_lock l{fdioInstance.lock};
diff --git a/src/async/match.cpp b/src/async/match.cpp
index bedce38..7d05ba6 100644
--- a/src/async/match.cpp
+++ b/src/async/match.cpp
@@ -42,7 +42,7 @@
     }
 }
 
-void match_ns::match_completion::arm() noexcept
+void match_ns::match_completion::start() noexcept
 {
     // Set ourselves as the awaiting Receiver and see if there is a message
     // to immediately complete on.
diff --git a/src/async/mutex.cpp b/src/async/mutex.cpp
index 44694c6..19e5d3c 100644
--- a/src/async/mutex.cpp
+++ b/src/async/mutex.cpp
@@ -34,7 +34,7 @@
 namespace mutex_ns
 {
 
-void mutex_completion::arm() noexcept
+void mutex_completion::start() noexcept
 {
     std::unique_lock l{mutexInstance.lock};