summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2023-11-01 21:36:15 +0300
committerEd Tanous <ed@tanous.net>2024-04-04 01:51:36 +0300
commit8099c51796bf6f94ad5fbb1f6844d700f498d3bb (patch)
tree5d99081be81b028b1756622015332de872ef661f /redfish-core
parent8e5cc7bdbf8727e9527d23973f81702799e80bd8 (diff)
downloadbmcweb-8099c51796bf6f94ad5fbb1f6844d700f498d3bb.tar.xz
Allow parsing null or value classes
In Redfish schema, just about all values can be a type (string, EDM.Numeric, etc) or null. Most APIs don't allow explicitly setting null, but there are a few cases where it is useful, namely in lists, where an an empty object {} keeps the value the same, and null deletes the value from the list. Previously we handled this by unpacking as nlohmann::json, but this allowed things like [1.0, {}] to pass the check for an array of string values. We'd ideally like to reject the 1.0 at the first stage, as well as reduce the number of tiered readJson calls that we make. This commit introducess support for unpacking std::variant types, that allows unpacking a known type, or explicitly allowing null, by unpacking std::nullptr_t. Tested: Unit tests pass. Change-Id: Ic7451877c824ac743faf1951cc2b5d9f8df8019c Signed-off-by: Ed Tanous <edtanous@google.com>
Diffstat (limited to 'redfish-core')
-rw-r--r--redfish-core/include/utils/json_utils.hpp78
1 files changed, 77 insertions, 1 deletions
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
index 0f4ba06a14..feb4e5460f 100644
--- a/redfish-core/include/utils/json_utils.hpp
+++ b/redfish-core/include/utils/json_utils.hpp
@@ -90,6 +90,14 @@ template <typename Type, std::size_t size>
struct IsStdArray<std::array<Type, size>> : std::true_type
{};
+template <typename Type>
+struct IsVariant : std::false_type
+{};
+
+template <typename... Types>
+struct IsVariant<std::variant<Types...>> : std::true_type
+{};
+
enum class UnpackErrorCode
{
success,
@@ -126,6 +134,29 @@ bool checkRange(const FromType& from, std::string_view key)
template <typename Type>
UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue,
+ std::string_view key, Type& value);
+
+template <std::size_t Index = 0, typename... Args>
+UnpackErrorCode unpackValueVariant(nlohmann::json& j, std::string_view key,
+ std::variant<Args...>& v)
+{
+ if constexpr (Index < std::variant_size_v<std::variant<Args...>>)
+ {
+ std::variant_alternative_t<Index, std::variant<Args...>> type;
+ UnpackErrorCode unpack = unpackValueWithErrorCode(j, key, type);
+ if (unpack == UnpackErrorCode::success)
+ {
+ v = std::move(type);
+ return unpack;
+ }
+
+ return unpackValueVariant<Index + 1, Args...>(j, key, v);
+ }
+ return UnpackErrorCode::invalidType;
+}
+
+template <typename Type>
+UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue,
std::string_view key, Type& value)
{
UnpackErrorCode ret = UnpackErrorCode::success;
@@ -188,6 +219,13 @@ UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue,
{
value = std::move(jsonValue);
}
+ else if constexpr (std::is_same_v<std::nullptr_t, Type>)
+ {
+ if (!jsonValue.is_null())
+ {
+ return UnpackErrorCode::invalidType;
+ }
+ }
else
{
using JsonType = std::add_const_t<std::add_pointer_t<Type>>;
@@ -252,6 +290,22 @@ bool unpackValue(nlohmann::json& jsonValue, std::string_view key,
ret;
}
}
+ else if constexpr (IsVariant<Type>::value)
+ {
+ UnpackErrorCode ec = unpackValueVariant(jsonValue, key, value);
+ if (ec != UnpackErrorCode::success)
+ {
+ if (ec == UnpackErrorCode::invalidType)
+ {
+ messages::propertyValueTypeError(res, jsonValue, key);
+ }
+ else if (ec == UnpackErrorCode::outOfRange)
+ {
+ messages::propertyValueNotInList(res, jsonValue, key);
+ }
+ return false;
+ }
+ }
else
{
UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value);
@@ -342,6 +396,16 @@ using UnpackVariant = std::variant<
std::string*,
nlohmann::json*,
nlohmann::json::object_t*,
+ std::variant<std::string, std::nullptr_t>*,
+ std::variant<uint8_t, std::nullptr_t>*,
+ std::variant<int16_t, std::nullptr_t>*,
+ std::variant<uint16_t, std::nullptr_t>*,
+ std::variant<int32_t, std::nullptr_t>*,
+ std::variant<uint32_t, std::nullptr_t>*,
+ std::variant<int64_t, std::nullptr_t>*,
+ std::variant<uint64_t, std::nullptr_t>*,
+ std::variant<double, std::nullptr_t>*,
+ std::variant<bool, std::nullptr_t>*,
std::vector<uint8_t>*,
std::vector<uint16_t>*,
std::vector<int16_t>*,
@@ -377,7 +441,19 @@ using UnpackVariant = std::variant<
std::optional<std::vector<double>>*,
std::optional<std::vector<std::string>>*,
std::optional<std::vector<nlohmann::json>>*,
- std::optional<std::vector<nlohmann::json::object_t>>*
+ std::optional<std::vector<nlohmann::json::object_t>>*,
+ std::optional<std::variant<std::string, std::nullptr_t>>*,
+ std::optional<std::variant<uint8_t, std::nullptr_t>>*,
+ std::optional<std::variant<int16_t, std::nullptr_t>>*,
+ std::optional<std::variant<uint16_t, std::nullptr_t>>*,
+ std::optional<std::variant<int32_t, std::nullptr_t>>*,
+ std::optional<std::variant<uint32_t, std::nullptr_t>>*,
+ std::optional<std::variant<int64_t, std::nullptr_t>>*,
+ std::optional<std::variant<uint64_t, std::nullptr_t>>*,
+ std::optional<std::variant<double, std::nullptr_t>>*,
+ std::optional<std::variant<bool, std::nullptr_t>>*,
+ std::optional<std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>*,
+ std::optional<std::variant<nlohmann::json::object_t, std::nullptr_t>>*
>;
// clang-format on