text: #pragma once
  
  #include <systemd/sd-bus.h>
  
  #include <sdbusplus/bus.hpp>
  #include <sdbusplus/sdbus.hpp>
  #include <sdbusplus/slot.hpp>
  #include <sdbusplus/vtable.hpp>
  
  #include <string>
  
  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
   *  inheritance, 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 : private sdbusplus::bus::details::bus_friend
  {
      /* Define all of the basic class operations:
       *     Not allowed:
       *         - Default constructor to avoid nullptrs.
       *         - Copy operations due to internal unique_ptr.
       *         - Move operations.
       *     Allowed:
       *         - Destructor.
       */
      interface() = delete;
      interface(const interface&) = delete;
      interface& operator=(const interface&) = delete;
      interface(interface&&) = delete;
      interface& operator=(interface&&) = delete;
  
      /** @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_t& bus, const char* path, const char* interf,
                const sdbusplus::vtable_t* vtable, void* context);
  
      ~interface();
  
      /** @brief Create a new signal message.
       *
       *  @param[in] member - The signal name to create.
       */
      auto new_signal(const char* member)
      {
          return _bus.new_signal(_path.c_str(), _interf.c_str(), member);
      }
  
      /** @brief Broadcast a property changed signal.
       *
       *  @param[in] property - The property which changed.
       */
      void property_changed(const char* property);
  
      /** @brief Emit the interface is added on D-Bus */
      void emit_added()
      {
          if (!_interface_added)
          {
              _bus.emit_interfaces_added(_path.c_str(), {_interf});
              _interface_added = true;
          }
      }
  
      /** @brief Emit the interface is removed on D-Bus */
      void emit_removed()
      {
          if (_interface_added)
          {
              _bus.emit_interfaces_removed(_path.c_str(), {_interf});
              _interface_added = false;
          }
      }
  
      bus_t& bus()
      {
          return _bus;
      }
      const std::string& path()
      {
          return _path;
      }
  
    private:
      bus_t _bus;
      std::string _path;
      std::string _interf;
      slot_t _slot{};
      SdBusInterface* _intf;
      bool _interface_added;
  };
  
  } // namespace interface
  
  using interface_t = interface::interface;
  
  } // namespace server
  } // namespace sdbusplus
  