From f6acdbec2c99670cf932d83cd797f08662e0b564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Hoz=C3=A1k?= Date: Thu, 16 Jun 2022 19:34:32 +0200 Subject: [PATCH] Allow disabling default enum conversions (#3536) --- CMakeLists.txt | 6 + cmake/ci.cmake | 4 +- docs/docset/docSet.sql | 1 + docs/mkdocs/docs/api/macros/index.md | 1 + .../macros/json_disable_enum_serialization.md | 135 ++++++++++++++++++ .../macros/nlohmann_json_serialize_enum.md | 1 + docs/mkdocs/docs/features/enum_conversion.md | 1 + docs/mkdocs/docs/features/macros.md | 6 + docs/mkdocs/mkdocs.yml | 1 + .../nlohmann/detail/conversions/from_json.hpp | 2 + .../nlohmann/detail/conversions/to_json.hpp | 2 + include/nlohmann/detail/macro_scope.hpp | 4 + include/nlohmann/detail/macro_unscope.hpp | 1 + single_include/nlohmann/json.hpp | 9 ++ 14 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md diff --git a/CMakeLists.txt b/CMakeLists.txt index aae5fb6e3..f20d56137 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ option(JSON_BuildTests "Build the unit tests when BUILD_TEST option(JSON_CI "Enable CI build targets." OFF) option(JSON_Diagnostics "Use extended diagnostic messages." OFF) option(JSON_ImplicitConversions "Enable implicit conversions." ON) +option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF) option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF) option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT}) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON) @@ -78,6 +79,10 @@ if (NOT JSON_ImplicitConversions) message(STATUS "Implicit conversions are disabled") endif() +if (JSON_DisableEnumSerialization) + message(STATUS "Enum integer serialization is disabled") +endif() + if (JSON_LegacyDiscardedValueComparison) message(STATUS "Legacy discarded value comparison enabled") endif() @@ -106,6 +111,7 @@ target_compile_definitions( ${NLOHMANN_JSON_TARGET_NAME} INTERFACE $<$>:JSON_USE_IMPLICIT_CONVERSIONS=0> + $<$:JSON_DISABLE_ENUM_SERIALIZATION=1> $<$:JSON_DIAGNOSTICS=1> $<$:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1> ) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 8704d4a54..4fcff86aa 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -838,8 +838,8 @@ endfunction() ci_get_cmake(3.1.0 CMAKE_3_1_0_BINARY) ci_get_cmake(3.13.0 CMAKE_3_13_0_BINARY) -set(JSON_CMAKE_FLAGS_3_1_0 JSON_Diagnostics JSON_ImplicitConversions JSON_LegacyDiscardedValueComparison - JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind) +set(JSON_CMAKE_FLAGS_3_1_0 JSON_Diagnostics JSON_ImplicitConversions JSON_DisableEnumSerialization + JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind) set(JSON_CMAKE_FLAGS_3_13_0 JSON_BuildTests) function(ci_add_cmake_flags_targets flag min_version) diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index 8bd4e0678..30c4a48de 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -140,6 +140,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('SAX Interface', 'Guide', 'fea INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'features/macros/index.html#json_assertx'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'features/macros/index.html#json_catch_userexception'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'features/macros/index.html#json_diagnostics'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'features/macros/index.html#json_disable_enum_serialization'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'features/macros/index.html#json_has_cpp_11-json_has_cpp_14-json_has_cpp_17-json_has_cpp_20'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'features/macros/index.html#json_has_cpp_11-json_has_cpp_14-json_has_cpp_17-json_has_cpp_20'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'features/macros/index.html#json_has_cpp_11-json_has_cpp_14-json_has_cpp_17-json_has_cpp_20'); diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index 5f0a7a194..d95869b93 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -29,6 +29,7 @@ header. See also the [macro overview page](../../features/macros.md). ## Type conversions +- [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums - [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions diff --git a/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md new file mode 100644 index 000000000..ea291f9a0 --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md @@ -0,0 +1,135 @@ +# JSON_DISABLE_ENUM_SERIALIZATION + +```cpp +#define JSON_DISABLE_ENUM_SERIALIZATION +``` + +When defined, default serialization and deserialization functions for enums are excluded and have to be provided by the user, for example, using [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) (see [arbitrary type conversions](../../features/arbitrary_types.md) for more details). + +Parsing or serializing an enum will result in a compiler error. + +This works for both unscoped and scoped enums. + +## Default definition + +By default, `#!cpp JSON_DISABLE_ENUM_SERIALIZATION` is not defined. + +```cpp +#undef JSON_DISABLE_ENUM_SERIALIZATION +``` + +## Examples + +??? example "Example 1: Disabled behavior" + + The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, meaning the code below **does not** compile. + + ```cpp + #define JSON_DISABLE_ENUM_SERIALIZATION 1 + #include + + using json = nlohmann::json; + + enum class Choice + { + first, + second, + }; + + int main() + { + // normally invokes to_json serialization function but with JSON_DISABLE_ENUM_SERIALIZATION defined, it does not + const json j = Choice::first; + + // normally invokes from_json parse function but with JSON_DISABLE_ENUM_SERIALIZATION defined, it does not + Choice ch = j.get(); + } + ``` + +??? example "Example 2: Serialize enum macro" + + The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, but uses [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) to parse and serialize the enum. + + ```cpp + #define JSON_DISABLE_ENUM_SERIALIZATION 1 + #include + + using json = nlohmann::json; + + enum class Choice + { + first, + second, + }; + + NLOHMANN_JSON_SERIALIZE_ENUM(Choice, + { + { Choice::first, "first" }, + { Choice::second, "second" }, + }) + + int main() + { + // uses user-defined to_json function defined by macro + const json j = Choice::first; + + // uses user-defined from_json function defined by macro + Choice ch = j.get(); + } + ``` + +??? example "Example 3: User-defined serialization/deserialization functions" + + The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, but uses user-defined functions to parse and serialize the enum. + + ```cpp + #define JSON_DISABLE_ENUM_SERIALIZATION 1 + #include + + using json = nlohmann::json; + + enum class Choice + { + first, + second, + }; + + void from_json(const json& j, Choice& ch) + { + auto value = j.get(); + if (value == "first") + { + ch = Choice::first; + } + else if (value == "second") + { + ch = Choice::second; + } + } + + void to_json(json& j, const Choice& ch) + { + auto value = j.get(); + if (value == "first") + { + ch = Choice::first; + } + else if (value == "second") + { + ch = Choice::second; + } + } + + int main() + { + // uses user-defined to_json function + const json j = Choice::first; + + // uses user-defined from_json function + Choice ch = j.get(); + } + ``` + +## See also + +- [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) \ No newline at end of file diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md index 7b0f89802..b7204a808 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md @@ -78,6 +78,7 @@ inline void from_json(const BasicJsonType& j, type& e); ## See also - [Specializing enum conversion](../../features/enum_conversion.md) +- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md) ## Version history diff --git a/docs/mkdocs/docs/features/enum_conversion.md b/docs/mkdocs/docs/features/enum_conversion.md index 7e61f67bb..59ffbd5f1 100644 --- a/docs/mkdocs/docs/features/enum_conversion.md +++ b/docs/mkdocs/docs/features/enum_conversion.md @@ -58,3 +58,4 @@ Other Important points: default pair carefully. - If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON. +- To disable the default serialization of enumerators as integers and force a compiler error instead, see [`JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index e04a426a5..1be95d35d 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -54,6 +54,12 @@ Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. See [full documentation of `JSON_NOEXCEPTION`](../api/macros/json_noexception.md). +## `JSON_DISABLE_ENUM_SERIALIZATION` + +When defined, default parse and serialize functions for enums are excluded and have to be provided by the user, for example, using [`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md). + +See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). + ## `JSON_NO_IO` When defined, headers ``, ``, ``, ``, and `` are not included and parse functions diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 08ef336db..c583ed78f 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -241,6 +241,7 @@ nav: - 'JSON_ASSERT': api/macros/json_assert.md - 'JSON_CATCH_USER': api/macros/json_throw_user.md - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md + - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md - 'JSON_HAS_CPP_11': api/macros/json_has_cpp_11.md - 'JSON_HAS_CPP_14': api/macros/json_has_cpp_11.md - 'JSON_HAS_CPP_17': api/macros/json_has_cpp_11.md diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index f0a93f291..ed4e6de5f 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -139,6 +139,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_int get_arithmetic_value(j, val); } +#if !JSON_DISABLE_ENUM_SERIALIZATION template::value, int> = 0> inline void from_json(const BasicJsonType& j, EnumType& e) @@ -147,6 +148,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) get_arithmetic_value(j, val); e = static_cast(val); } +#endif // JSON_DISABLE_ENUM_SERIALIZATION // forward_list doesn't have an insert method template::construct(j, static_cast(val)); } +#if !JSON_DISABLE_ENUM_SERIALIZATION template::value, int> = 0> inline void to_json(BasicJsonType& j, EnumType e) noexcept @@ -320,6 +321,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept using underlying_type = typename std::underlying_type::type; external_constructor::construct(j, static_cast(e)); } +#endif // JSON_DISABLE_ENUM_SERIALIZATION template inline void to_json(BasicJsonType& j, const std::vector& e) diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 18a527c19..706f1b971 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -456,3 +456,7 @@ #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 396fe1a33..09f677b3d 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -16,6 +16,7 @@ #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS +#undef JSON_DISABLE_ENUM_SERIALIZATION #ifndef JSON_TEST_KEEP_MACROS #undef JSON_CATCH diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 4a9c4bf83..98c8dd664 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2684,6 +2684,10 @@ using is_detected_convertible = #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + #if JSON_HAS_THREE_WAY_COMPARISON #include // partial_ordering #endif @@ -4384,6 +4388,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_int get_arithmetic_value(j, val); } +#if !JSON_DISABLE_ENUM_SERIALIZATION template::value, int> = 0> inline void from_json(const BasicJsonType& j, EnumType& e) @@ -4392,6 +4397,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e) get_arithmetic_value(j, val); e = static_cast(val); } +#endif // JSON_DISABLE_ENUM_SERIALIZATION // forward_list doesn't have an insert method template::construct(j, static_cast(val)); } +#if !JSON_DISABLE_ENUM_SERIALIZATION template::value, int> = 0> inline void to_json(BasicJsonType& j, EnumType e) noexcept @@ -5301,6 +5308,7 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept using underlying_type = typename std::underlying_type::type; external_constructor::construct(j, static_cast(e)); } +#endif // JSON_DISABLE_ENUM_SERIALIZATION template inline void to_json(BasicJsonType& j, const std::vector& e) @@ -23580,6 +23588,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS +#undef JSON_DISABLE_ENUM_SERIALIZATION #ifndef JSON_TEST_KEEP_MACROS #undef JSON_CATCH