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