object: add binding for 'sd_bus_emit_object_added/removed
Change-Id: I450715fb47c975737f9326c3c945da762c53accb
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/bus.hpp b/sdbusplus/bus.hpp
index eae7cd2..fe68690 100644
--- a/sdbusplus/bus.hpp
+++ b/sdbusplus/bus.hpp
@@ -11,6 +11,7 @@
// Forward declare.
namespace server { namespace interface { struct interface; } }
namespace server { namespace manager { struct manager; } }
+namespace server { namespace object { template<class...> struct object; } }
namespace bus
{
@@ -144,6 +145,7 @@
friend struct server::interface::interface;
friend struct server::manager::manager;
+ template<class... Args> friend struct server::object::object;
private:
busp_t get() { return _bus.get(); }
diff --git a/sdbusplus/object.hpp b/sdbusplus/object.hpp
new file mode 100644
index 0000000..421dc53
--- /dev/null
+++ b/sdbusplus/object.hpp
@@ -0,0 +1,115 @@
+#pragma once
+#include <sdbusplus/bus.hpp>
+
+namespace sdbusplus
+{
+
+namespace server
+{
+
+namespace object
+{
+
+namespace details
+{
+
+/** Templates to allow multiple inheritence via template parameters.
+ *
+ * These allow an object to group multiple dbus interface bindings into a
+ * single class.
+ */
+template <class T, class... Rest> struct compose_impl :
+ T, compose_impl<Rest...>
+{
+ compose_impl(bus::bus& bus, const char* path) :
+ T(bus, path), compose_impl<Rest...>(bus, path) {}
+};
+
+/** Specialization for single element. */
+template <class T> struct compose_impl<T> : T
+{
+ compose_impl(bus::bus& bus, const char* path) :
+ T(bus, path) {}
+};
+
+/** Default compose operation for variadic arguments. */
+template <class... Args> struct compose : compose_impl<Args...>
+{
+ compose(bus::bus& bus, const char* path) :
+ compose_impl<Args...>(bus, path) {}
+};
+
+/** Specialization for zero variadic arguments. */
+template <> struct compose<>
+{
+ compose(bus::bus& bus, const char* path) {}
+};
+
+} // namespace details
+
+/** Class to compose multiple dbus interfaces and object signals.
+ *
+ * Any number of classes representing a dbus interface may be composed into
+ * a single dbus object. The interfaces will be created first and hooked
+ * into the object space via the 'add_object_vtable' calls. Afterwards,
+ * a signal will be emitted for the whole object to indicate all new
+ * interfaces via 'sd_bus_emit_object_added'.
+ *
+ * Similar, on destruction, the interfaces are removed (unref'd) and the
+ * 'sd_bus_emit_object_removed' signals are emitted.
+ *
+ */
+template<class... Args>
+struct object : details::compose<Args...>
+{
+ /* Define all of the basic class operations:
+ * Not allowed:
+ * - Default constructor to avoid nullptrs.
+ * - Copy operations due to internal unique_ptr.
+ * Allowed:
+ * - Move operations.
+ * - Destructor.
+ */
+ object() = delete;
+ object(const object&) = delete;
+ object& operator=(const object&) = delete;
+ object(object&&) = default;
+ object& operator=(object&&) = default;
+
+ /** Construct an 'object' on a bus with a path.
+ *
+ * @param[in] bus - The bus to place the object on.
+ * @param[in] path - The path the object resides at.
+ */
+ object(bus::bus& bus,
+ const char* path)
+ : details::compose<Args...>(bus, path),
+ __sdbusplus_server_object_bus(sd_bus_ref(bus.get())),
+ __sdbusplus_server_object_path(path)
+ {
+ sd_bus_emit_object_added(__sdbusplus_server_object_bus.get(),
+ __sdbusplus_server_object_path.c_str());
+ }
+
+ ~object()
+ {
+ sd_bus_emit_object_removed(__sdbusplus_server_object_bus.get(),
+ __sdbusplus_server_object_path.c_str());
+ }
+
+ private:
+ // These member names are purposefully chosen as long and, hopefully,
+ // unique. Since an object is 'composed' via multiple-inheritence,
+ // all members need to have unique names to ensure there is no
+ // ambiguity.
+ bus::bus __sdbusplus_server_object_bus;
+ std::string __sdbusplus_server_object_path;
+
+};
+
+} // namespace object
+
+template <class... Args> using object_t = object::object<Args...>;
+
+} // namespace server
+} // namespace sdbusplus