interface: add binding for sd_bus_add_object_vtable

Change-Id: I27ca62e107204ed8bf0b295cc22ddd56ca380568
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/bus.hpp b/sdbusplus/bus.hpp
index bbbf831..0156705 100644
--- a/sdbusplus/bus.hpp
+++ b/sdbusplus/bus.hpp
@@ -7,6 +7,10 @@
 
 namespace sdbusplus
 {
+
+// Forward declare.
+namespace server { namespace interface { struct interface; } }
+
 namespace bus
 {
 
@@ -161,7 +165,10 @@
         b.call_noreply(m);
     }
 
+    friend struct server::interface::interface;
+
     private:
+        busp_t get() { return _bus.get(); }
         details::bus _bus;
 };
 
diff --git a/sdbusplus/interface.hpp b/sdbusplus/interface.hpp
new file mode 100644
index 0000000..da1f9fc
--- /dev/null
+++ b/sdbusplus/interface.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <systemd/sd-bus.h>
+#include <sdbusplus/slot.hpp>
+#include <sdbusplus/vtable.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace sdbusplus
+{
+
+namespace server
+{
+
+namespace interface
+{
+
+/** @class interface
+ *  @brief Provide a C++ holder for dbus interface instances.
+ *
+ *  Wraps sd_bus_add_object_vtable so that the interface is registered
+ *  on construction and deregistered on destruction.
+ *
+ *  @note This class is 'final' because it is expected to be used by an
+ *  implementation of a class representing a dbus interface, which will be
+ *  composed through multiple-inheritence to create a single dbus 'object'.
+ *  Marking it 'final' prevents users from using an 'is-a' relationship via
+ *  inheritence, which might be a natural option.  Instead, a dbus interface
+ *  implementation should 'has-a' server::interface with a name sufficiently
+ *  unique to prevent name collisions in multiple-inheritence situations.
+ */
+struct interface final
+{
+        /* 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.
+         */
+    interface() = delete;
+    interface(const interface&) = delete;
+    interface& operator=(const interface&) = delete;
+    interface(interface&&) = default;
+    interface& operator=(interface&&) = default;
+    ~interface() = default;
+
+    /** @brief Register the (path, interface, vtable) as a dbus object.
+     *
+     *  @param[in] bus - The bus to register on.
+     *  @param[in] path - The path to register as.
+     *  @param[in] interf - The interface to register as.
+     *  @param[in] vtable - The vtable to register.
+     *  @param[in] context - User-defined context, which is often 'this' from
+     *                       the interface implementation class.
+     */
+    interface(sdbusplus::bus::bus& bus,
+              const char* path,
+              const char* interf,
+              const sdbusplus::vtable::vtable_t* vtable,
+              void* context) : _slot(nullptr)
+    {
+        sd_bus_slot* slot = nullptr;
+        sd_bus_add_object_vtable(bus.get(), &slot, path, interf,
+                                 vtable, context);
+
+        _slot = decltype(_slot){slot};
+    }
+
+    private:
+        slot::slot _slot;
+};
+
+} // namespace interface
+} // namespace server
+} // namespace sdbusplus