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()