Set properties when constructing interfaces.

Make use of new sdbusplus support for passing a map
of properties and their values to the interface
constructor.

Change-Id: Ib0dd406fd80c89acb723e3a376af26ba57b53d27
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/manager.cpp b/manager.cpp
index 1d1f778..5dcd9e5 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -16,6 +16,7 @@
 #include <iostream>
 #include <exception>
 #include <chrono>
+#include <log.hpp>
 #include "manager.hpp"
 
 using namespace std::literals::chrono_literals;
@@ -192,53 +193,60 @@
 
     for (auto& o : objs)
     {
-        auto& relPath = o.first;
-        auto& ifaces = o.second;
-
-        absPath.assign(_root);
-        absPath.append(relPath);
-
-        auto obj = _refs.find(absPath);
-        if (obj != _refs.end())
+        try
         {
-            // This object already exists...skip.
-            continue;
-        }
+            auto& relPath = o.first;
+            auto& ifaces = o.second;
 
-        // Create an interface holder for each interface
-        // provided by the client and group them into
-        // a container.
-        InterfaceComposite ref;
+            absPath.assign(_root);
+            absPath.append(relPath);
 
-        for (auto& iface : ifaces)
-        {
-            auto& props = iface.second;
-            auto pMakers = _makers.find(iface.first.c_str());
-
-            if (pMakers == _makers.end())
+            auto obj = _refs.find(absPath);
+            if (obj != _refs.end())
             {
-                // This interface is not known.
+                // This object already exists...skip.
                 continue;
             }
 
-            auto& maker = std::get<MakerType>(pMakers->second);
+            // Create an interface holder for each interface
+            // provided by the client and group them into
+            // a container.
+            InterfaceComposite ref;
 
-            ref.emplace(
-                iface.first,
-                maker(
-                    _bus,
-                    absPath.c_str(),
-                    props));
+            for (auto& iface : ifaces)
+            {
+                auto& props = iface.second;
+                auto pMakers = _makers.find(iface.first.c_str());
+
+                if (pMakers == _makers.end())
+                {
+                    // This interface is not known.
+                    continue;
+                }
+
+                auto& maker = std::get<MakerType>(pMakers->second);
+
+                ref.emplace(
+                    iface.first,
+                    maker(
+                        _bus,
+                        absPath.c_str(),
+                        props));
+            }
+
+            if (!ref.empty())
+            {
+                // Hang on to a reference to the object (interfaces)
+                // so it stays on the bus, and so we can make calls
+                // to it if needed.
+                _refs.emplace(
+                    absPath, std::move(ref));
+                _bus.emit_object_added(absPath.c_str());
+            }
         }
-
-        if (!ref.empty())
+        catch (const std::exception& e)
         {
-            // Hang on to a reference to the object (interfaces)
-            // so it stays on the bus, and so we can make calls
-            // to it if needed.
-            _refs.emplace(
-                absPath, std::move(ref));
-            _bus.emit_object_added(absPath.c_str());
+            logging::log<logging::level::ERR>(e.what());
         }
     }
 }
diff --git a/manager.hpp b/manager.hpp
index 5e0930b..806a9a4 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -39,8 +39,20 @@
         const char* path,
         const Interface& props)
     {
-        // TODO: pass props to import constructor...
-        return any_ns::any(std::make_shared<T>(bus, path));
+        using PropertiesVariant = typename T::PropertiesVariant;
+        using InterfaceVariant =
+            std::map<std::string, PropertiesVariant>;
+
+        InterfaceVariant v;
+
+        for (const auto& p : props)
+        {
+            v.emplace(
+                p.first,
+                convertVariant<PropertiesVariant>(p.second));
+        }
+
+        return any_ns::any(std::make_shared<T>(bus, path, v));
     }
 };
 
diff --git a/test/test.cpp b/test/test.cpp
index 0a941f7..d36aa24 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -207,7 +207,7 @@
         },
         {
             "xyz.openbmc_project.Example.Iface2",
-            {{"ExampleProperty2", "test2"s}}
+            {{"ExampleProperty2", "test2"s}, {"ExampleProperty3", 0ll}}
         },
     };
 
diff --git a/utils.hpp b/utils.hpp
index 33de439..60119be 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -6,7 +6,69 @@
 {
 namespace manager
 {
+/** @struct MakeVariantVisitor
+ *  @brief Return a variant if the visited type is a possible variant type.
+ *
+ *  @tparam V - The desired variant type.
+ */
+template <typename V>
+struct MakeVariantVisitor
+{
+    /** @struct Make
+     *  @brief Return variant visitor.
+     *
+     *  @tparam T - The variant type to return.
+     *  @tparam Arg - The type being visited in the source variant.
+     *  @tparam Enable - Overload resolution removal.
+     */
+    template <typename T, typename Arg, typename Enable = void>
+    struct Make
+    {
+        static auto make(Arg&& arg)
+        {
+            throw sdbusplus::message::variant_ns::bad_variant_access(
+                "in MakeVariantVisitor");
+            return T();
+        }
+    };
 
+    /** @struct Make
+     *  @brief Return variant visitor.
+     *
+     *  struct Make specialization if Arg is in T (int -> variant<int, char>).
+     */
+    template <typename T, typename Arg>
+    struct Make<T, Arg,
+               typename std::enable_if<std::is_convertible<Arg, T>::value>::type>
+    {
+        static auto make(Arg&& arg)
+        {
+            return T(std::forward<Arg>(arg));
+        }
+    };
+
+    /** @brief Make variant visitor.  */
+    template <typename Arg>
+    auto operator()(Arg&& arg) const
+    {
+        return Make<V, Arg>::make(arg);
+    }
+};
+
+/** @brief Convert variants with different contained types.
+ *
+ *  @tparam V - The desired variant type.
+ *  @tparam Arg - The source variant type.
+ *
+ *  @param[in] v - The source variant.
+ *  @returns - The converted variant.
+ */
+template <typename V, typename Arg>
+auto convertVariant(Arg&& v)
+{
+    return sdbusplus::message::variant_ns::apply_visitor(
+               MakeVariantVisitor<V>(), v);
+}
 } // namespace manager
 } // namespace inventory
 } // namespace phosphor