Skip to content

Commit 28866e1

Browse files
committed
add NLOHMANN_JSON_SERIALIZE_ENUM_STRICT macro that throws on unknown JSON value (Fixes #3992)
Signed-off-by: Ash-Jose <[email protected]>
1 parent a08ce4b commit 28866e1

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

include/nlohmann/detail/macro_scope.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,41 @@
224224
@since version 3.4.0
225225
*/
226226
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
227+
template<typename BasicJsonType> \
228+
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
229+
{ \
230+
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
231+
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
232+
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
233+
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
234+
auto it = std::find_if(std::begin(m), std::end(m), \
235+
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
236+
{ \
237+
return ej_pair.first == e; \
238+
}); \
239+
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
240+
} \
241+
template<typename BasicJsonType> \
242+
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
243+
{ \
244+
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
245+
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
246+
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
247+
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
248+
auto it = std::find_if(std::begin(m), std::end(m), \
249+
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
250+
{ \
251+
return ej_pair.second == j; \
252+
}); \
253+
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
254+
}
255+
256+
/*!
257+
@brief macro to briefly define a mapping between an enum and JSON (strict version)
258+
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
259+
@since version 3.12.0
260+
*/
261+
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
227262
template<typename BasicJsonType> \
228263
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
229264
{ \

single_include/nlohmann/json.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2588,6 +2588,41 @@ JSON_HEDLEY_DIAGNOSTIC_POP
25882588
@since version 3.4.0
25892589
*/
25902590
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
2591+
template<typename BasicJsonType> \
2592+
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
2593+
{ \
2594+
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
2595+
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2596+
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
2597+
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2598+
auto it = std::find_if(std::begin(m), std::end(m), \
2599+
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2600+
{ \
2601+
return ej_pair.first == e; \
2602+
}); \
2603+
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
2604+
} \
2605+
template<typename BasicJsonType> \
2606+
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
2607+
{ \
2608+
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
2609+
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2610+
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
2611+
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2612+
auto it = std::find_if(std::begin(m), std::end(m), \
2613+
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2614+
{ \
2615+
return ej_pair.second == j; \
2616+
}); \
2617+
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
2618+
}
2619+
2620+
/*!
2621+
@brief macro to briefly define a mapping between an enum and JSON (strict version)
2622+
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
2623+
@since version 3.12.0
2624+
*/
2625+
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
25912626
template<typename BasicJsonType> \
25922627
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
25932628
{ \

tests/src/unit-serialize_enum_strict.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,23 @@ using json = nlohmann::json;
55
namespace ns {
66
enum class Color { red, green, blue, unknown };
77

8-
NLOHMANN_JSON_SERIALIZE_ENUM(Color, {
8+
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(Color, {
99
{ Color::unknown, "unknown" },
1010
{ Color::red, "red" },
1111
{ Color::green, "green" },
1212
{ Color::blue, "blue" }
1313
})
1414
} // namespace ns
1515

16-
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM throws on unknown input string")
16+
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT throws on unknown input string")
1717
{
1818
json j = "purple"; // not mapped
1919
ns::Color c;
2020

2121
CHECK_THROWS_AS((j.get_to(c)), nlohmann::detail::type_error);
2222
}
2323

24-
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM still deserializes valid values")
24+
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT still deserializes valid values")
2525
{
2626
json j = "green";
2727
auto c = j.get<ns::Color>();

0 commit comments

Comments
 (0)