async: switch to stdexec async_scope

Use the `async_scope` implementation from stdexec instead of the
custom `scope` class here, which greatly reduces our own code and
also aligns better with the C++ STL direction.  The major changes are
around exception paths:

    - Spawned tasks which end with an exception will now std::terminate,
      so any task expected to throw should have an `upon_error` chain.

    - Spawned tasks which are stopped will be no longer throw an
      `UnexpectedStop` exception, so they should be chained with an
      `upon_stopped` if this is important.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I4e0c85712652efa5b296b898dcc2b0026ba4c625
diff --git a/src/async/context.cpp b/src/async/context.cpp
index 1da888c..85e0200 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -39,7 +39,10 @@
     context& ctx;
     event_t::time_resolution timeout{};
 
-    static task<> loop(context& ctx);
+    // TODO: It seems like we should be able to do a normal `task<>` here
+    //       but spawn on it compile fails.
+    static exec::basic_task<void, exec::__task::__raw_task_context<void>>
+        loop(context& ctx);
     static void wait_once(context& ctx);
 };
 
@@ -99,7 +102,8 @@
     context& ctx;
 };
 
-task<> wait_process_completion::loop(context& ctx)
+exec::basic_task<void, exec::__task::__raw_task_context<void>>
+    wait_process_completion::loop(context& ctx)
 {
     while (!ctx.final_stop.stop_requested())
     {
@@ -142,10 +146,7 @@
     wait_for_wait_process_stopped();
 
     // Wait for all the internal tasks to complete.
-    stdexec::sync_wait(internal_tasks.empty() |
-                       execution::upon_error([&](auto&& e) {
-                           pending_exceptions.emplace_back(std::move(e));
-                       }));
+    stdexec::sync_wait(internal_tasks.on_empty());
 
     // Finish up the loop and join the thread.
     // (There shouldn't be anything going on by this point anyhow.)
@@ -162,8 +163,7 @@
 void context::worker_run()
 {
     // Start the sdbus 'wait/process' loop; treat it as an internal task.
-    internal_tasks.spawn(details::wait_process_completion::loop(*this) |
-                         execution::upon_stopped([]() {}));
+    internal_tasks.spawn(details::wait_process_completion::loop(*this));
 
     // Run the execution::run_loop to handle all the tasks.
     loop.run();
@@ -212,11 +212,8 @@
     }
 
     // Spawn the watch for completion / exceptions.
-    internal_tasks.spawn(pending_tasks.empty() |
-                         execution::then([this]() { spawn_complete(); }) |
-                         execution::upon_error([this](auto&& e) {
-                             spawn_complete(std::move(e));
-                         }));
+    internal_tasks.spawn(pending_tasks.on_empty() |
+                         execution::then([this]() { spawn_complete(); }));
 }
 
 void context::caller_run()
diff --git a/src/async/scope.cpp b/src/async/scope.cpp
deleted file mode 100644
index d9eb8a7..0000000
--- a/src/async/scope.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include <sdbusplus/async/scope.hpp>
-
-#include <exception>
-
-namespace sdbusplus::async
-{
-scope::~scope() noexcept(false)
-{
-    if (pending_count != 0)
-    {
-        throw std::logic_error(
-            "sdbusplus::async::scope destructed while tasks are pending.");
-    }
-}
-
-void scope::started_task() noexcept
-{
-    std::lock_guard l{lock};
-    started = true;
-    ++pending_count;
-}
-
-void scope::ended_task(std::exception_ptr&& e) noexcept
-{
-    scope_ns::scope_completion* p = nullptr;
-
-    {
-        std::lock_guard l{lock};
-        --pending_count; // decrement count.
-
-        if (e)
-        {
-            pending_exceptions.emplace_back(std::exchange(e, {}));
-        }
-
-        // If the scope is complete, get the pending completion, if it exists.
-        if (!pending_exceptions.empty() || (pending_count == 0))
-        {
-            p = std::exchange(pending, nullptr);
-        }
-    }
-
-    if (p)
-    {
-        std::exception_ptr fwd_exception = {};
-        if (!pending_exceptions.empty())
-        {
-            fwd_exception = pending_exceptions.front();
-            pending_exceptions.pop_front();
-        }
-        p->complete(std::move(fwd_exception));
-    }
-}
-
-scope_ns::scope_sender scope::empty() noexcept
-{
-    return scope_ns::scope_sender(*this);
-}
-
-namespace scope_ns
-{
-void scope_completion::arm() noexcept
-{
-    bool done = false;
-    std::exception_ptr e{};
-
-    {
-        std::lock_guard l{s.lock};
-        if (!s.started)
-        {
-            done = false;
-        }
-        else if (!s.pending_exceptions.empty())
-        {
-            e = s.pending_exceptions.front();
-            s.pending_exceptions.pop_front();
-            done = true;
-        }
-        else if (s.pending_count == 0)
-        {
-            done = true;
-        }
-        else
-        {
-            s.pending = this;
-        }
-    }
-
-    if (done)
-    {
-        this->complete(std::move(e));
-    }
-}
-} // namespace scope_ns
-
-} // namespace sdbusplus::async