async: add context_ref class for CRTP patterns
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I6364f6f5a654ec0c628112637014ae2daed5d740
diff --git a/include/sdbusplus/async/client.hpp b/include/sdbusplus/async/client.hpp
index 4bece52..ab2e9e9 100644
--- a/include/sdbusplus/async/client.hpp
+++ b/include/sdbusplus/async/client.hpp
@@ -18,10 +18,10 @@
*/
template <bool S, bool P, bool Preserved, template <typename> typename... Types>
class client :
+ public context_ref,
public Types<sdbusplus::async::proxy_ns::proxy<S, P, false, Preserved>>...
{
private:
- sdbusplus::async::context& ctx;
sdbusplus::async::proxy_ns::proxy<S, P, false, Preserved> proxy{};
public:
@@ -33,14 +33,14 @@
/* Default (empty) constructor only when Service and Path are missing. */
explicit client(sdbusplus::async::context& ctx)
requires(!S && !P)
- : Types<decltype(proxy)>(ctx, decltype(proxy){})..., ctx(ctx)
+ : context_ref(ctx), Types<decltype(proxy)>(ctx, decltype(proxy){})...
{}
/* Conversion constructor for a non-empty (Service and/or Path) proxy. */
explicit client(sdbusplus::async::context& ctx,
sdbusplus::async::proxy_ns::proxy<S, P, false, Preserved> p)
requires(S || P)
- : Types<decltype(proxy)>(ctx, p)..., ctx(ctx), proxy(p)
+ : context_ref(ctx), Types<decltype(proxy)>(ctx, p)..., proxy(p)
{}
/* Convert a non-Service instance to a Service instance. */
diff --git a/include/sdbusplus/async/context.hpp b/include/sdbusplus/async/context.hpp
index 96cb38d..40356d5 100644
--- a/include/sdbusplus/async/context.hpp
+++ b/include/sdbusplus/async/context.hpp
@@ -125,6 +125,25 @@
static int dbus_event_handle(sd_event_source*, int, uint32_t, void*);
};
+/** @brief Simple holder of a context&
+ *
+ * A common pattern is for classes to hold a reference to a
+ * context. Add a class that can be inherited instead of
+ * having as a class member. This allows the context-ref constructor to be
+ * placed earliest in the ctor initializer list, so that the reference can be
+ * available from inherited classes (ex. for CRTP patterns).
+ *
+ */
+class context_ref
+{
+ public:
+ context_ref() = delete;
+ explicit context_ref(context& ctx) : ctx(ctx) {}
+
+ protected:
+ context& ctx;
+};
+
namespace details
{
struct context_friend
diff --git a/include/sdbusplus/async/timer.hpp b/include/sdbusplus/async/timer.hpp
index 699265a..909fad3 100644
--- a/include/sdbusplus/async/timer.hpp
+++ b/include/sdbusplus/async/timer.hpp
@@ -29,13 +29,13 @@
* On callback, completes the Receiver.
*/
template <execution::receiver R>
-struct sleep_operation : public details::context_friend
+struct sleep_operation : public context_ref, details::context_friend
{
sleep_operation() = delete;
sleep_operation(sleep_operation&&) = delete;
sleep_operation(context& ctx, event_t::time_resolution time, R&& r) :
- ctx(ctx), time(time), receiver(std::move(r))
+ context_ref(ctx), time(time), receiver(std::move(r))
{}
static int handler(sd_event_source*, uint64_t, void* data) noexcept
@@ -66,7 +66,6 @@
return get_event_loop(ctx);
}
- context& ctx;
event_t::time_resolution time;
event_source_t source;
R receiver;
@@ -76,14 +75,14 @@
*
* On connect, instantiates the completion event.
*/
-struct sleep_sender : public details::context_friend
+struct sleep_sender : public context_ref, details::context_friend
{
using is_sender = void;
sleep_sender() = delete;
sleep_sender(context& ctx, event_t::time_resolution time) noexcept :
- ctx(ctx), time(time)
+ context_ref(ctx), time(time)
{}
friend auto tag_invoke(execution::get_completion_signatures_t,
@@ -110,7 +109,6 @@
}
private:
- context& ctx;
event_t::time_resolution time;
};
diff --git a/src/async/context.cpp b/src/async/context.cpp
index 5a5bc8c..5bb58ae 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -22,9 +22,9 @@
* task `co_await`ing Senders over and over. This class is the completion
* handling for the Sender (to get it back to the Receiver, ie. the worker).
*/
-struct wait_process_completion : bus::details::bus_friend
+struct wait_process_completion : context_ref, bus::details::bus_friend
{
- explicit wait_process_completion(context& ctx) : ctx(ctx) {}
+ explicit wait_process_completion(context& ctx) : context_ref(ctx) {}
virtual ~wait_process_completion() = default;
// Called by the `caller` to indicate the Sender is completed.
@@ -36,7 +36,6 @@
void arm() noexcept;
// Data to share with the worker.
- context& ctx;
event_t::time_resolution timeout{};
// TODO: It seems like we should be able to do a normal `task<>` here
@@ -82,11 +81,11 @@
};
/* The sender for the wait/process event. */
-struct wait_process_sender
+struct wait_process_sender : public context_ref
{
using is_sender = void;
- explicit wait_process_sender(context& ctx) : ctx(ctx) {}
+ explicit wait_process_sender(context& ctx) : context_ref(ctx) {}
friend auto tag_invoke(execution::get_completion_signatures_t,
const wait_process_sender&, auto)
@@ -99,9 +98,6 @@
// Create the completion for the wait.
return {self.ctx, std::move(r)};
}
-
- private:
- context& ctx;
};
exec::basic_task<void, exec::__task::__raw_task_context<void>>