monitor:JSON: Add JSON variant type handler

Runtime determination of a configured JSON entry's data type that's
parsed into a variant needs a special handler for each type that the
variant could contain. This uses the JSON entry's determined type unless
an optional type is given to parse it as that data type, which must be
supported in the variant the JSON entry's value is stored in.

Tested:
    Exception thrown when an unsupported type is configured
    Supported types are parsed and returned within the variant
    No configured type given results in returning JSON determined type

Change-Id: I3e5be5b369eb53fec2025ec19f235df927fbb3d8
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/monitor/types.hpp b/monitor/types.hpp
index c827042..66f2dfe 100644
--- a/monitor/types.hpp
+++ b/monitor/types.hpp
@@ -2,6 +2,9 @@
 
 #include "trust_group.hpp"
 
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/log.hpp>
+
 #include <experimental/optional>
 #include <functional>
 #include <string>
@@ -21,6 +24,66 @@
 using PropertyIdentity = std::tuple<std::string, std::string, std::string>;
 
 using PropertyValue = std::variant<bool, int64_t, std::string>;
+class JsonTypeHandler
+{
+    using json = nlohmann::json;
+
+  public:
+    /**
+     * @brief Determines the data type of a JSON configured parameter that is
+     * used as a variant within the fan monitor application and returns the
+     * value as that variant.
+     * @details Retrieves a JSON entry by the first derived data type that
+     * is not null. Expected data types should appear in a logical order of
+     * conversion. i.e.) uint and int could both be uint Alternatively, the
+     * expected data type can be given to force which supported data type
+     * the JSON entry should be retrieved as.
+     *
+     * @param[in] entry - A single JSON entry
+     * @param[in] type - (OPTIONAL) The preferred data type of the entry
+     *
+     * @return A `PropertyValue` variant containing the JSON entry's value
+     */
+    static const PropertyValue getPropValue(const json& entry,
+                                            const std::string& type = "")
+    {
+        PropertyValue value;
+        if (auto boolPtr = entry.get_ptr<const bool*>())
+        {
+            if (type.empty() || type == "bool")
+            {
+                value = *boolPtr;
+                return value;
+            }
+        }
+        if (auto int64Ptr = entry.get_ptr<const int64_t*>())
+        {
+            if (type.empty() || type == "int64_t")
+            {
+                value = *int64Ptr;
+                return value;
+            }
+        }
+        if (auto stringPtr = entry.get_ptr<const std::string*>())
+        {
+            if (type.empty() || type == "std::string")
+            {
+                value = *stringPtr;
+                return value;
+            }
+        }
+
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Unsupported data type for JSON entry's value",
+            phosphor::logging::entry("GIVEN_ENTRY_TYPE=%s", type.c_str()),
+            phosphor::logging::entry("JSON_ENTRY=%s", entry.dump().c_str()),
+            phosphor::logging::entry("SUPPORTED_TYPES=%s",
+                                     "{bool, int64_t, std::string}"));
+        throw std::runtime_error(
+            "Unsupported data type for JSON entry's value");
+    }
+};
+
 constexpr auto propIdentity = 0;
 constexpr auto propValue = 1;
 using PropertyState = std::pair<PropertyIdentity, PropertyValue>;