utils: allow conversion from string to dbus enum

Enhance the variant visitor to leverage functionality in sdbusplus
that allows conversion of strings to enums (or variants containing
enums).  This will allow a seem-less transition for Inventory
properties which are defined as string and then transition to
enumerations, such as that introduced by [1].

Tested: Booted Witherspoon in QEMU with [1] and [2].  Confirmed PIM
no longer coredumps and successfully converts the string to an
enumeration.

1. https://github.com/openbmc/phosphor-dbus-interfaces/commit/178cae08d6b79eac7cf3eca963526eeefc53a5af
2. https://gerrit.openbmc-project.xyz/c/openbmc/openbmc/+/45005

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I341d3c6ffc0d36e63444c63351012ac487b171ef
diff --git a/utils.hpp b/utils.hpp
index 24ced13..298a91d 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <sdbusplus/message/types.hpp>
+#include <sdbusplus/message/native_types.hpp>
 
 #include <cstring>
 #include <stdexcept>
@@ -47,9 +47,8 @@
      *  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>
+    struct Make<T, Arg,
+                typename std::enable_if_t<std::is_convertible_v<Arg, T>>>
     {
         static auto make(Arg&& arg)
         {
@@ -57,6 +56,40 @@
         }
     };
 
+    /** @struct Make
+     *  @brief Return variant visitor.
+     *
+     *  struct Make specialization if Arg is a string, but not otherwise
+     *  directly convertable by C++ conversion constructors.  Strings might
+     *  be convertable using underlying sdbusplus routines, so give them an
+     *  attempt.
+     */
+    template <typename T, typename Arg>
+    struct Make<
+        T, Arg,
+        typename std::enable_if_t<
+            !std::is_convertible_v<Arg, T> &&
+            std::is_same_v<std::string,
+                           std::remove_cv_t<std::remove_reference_t<Arg>>> &&
+            sdbusplus::message::has_convert_from_string_v<T>>>
+    {
+        static auto make(Arg&& arg) -> T
+        {
+            auto r = sdbusplus::message::convert_from_string<T>(
+                std::forward<Arg>(arg));
+            if (r)
+            {
+                return *r;
+            }
+
+            throw std::runtime_error(
+                std::string("Invalid conversion in MakeVariantVisitor::") +
+                __PRETTY_FUNCTION__);
+
+            return {};
+        }
+    };
+
     /** @brief Make variant visitor.  */
     template <typename Arg>
     auto operator()(Arg&& arg) const