mirror of
https://github.com/nlohmann/json.git
synced 2026-05-19 04:35:23 +00:00
Serialize enum (#5151)
* Added NLOHNMANN_JSON_SERIALIZE_ENUM_STRICT - duplicate of NLOHMANN_JSON_SERIALIZE_ENUM Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * Added failing tests for NLOHMANN_JSON_SERIALIZE_ENUM_STRICT Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * modified NLOHMANN_JSON_SERIALIZE_STRICT to throw Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * added documentation and changed readme to include NLOHMANN_JSON_SERIALIZE_ENUM_STRICT Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * ran amalgamate Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * docs(macros): add page for JSON_SERIALIZE_ENUM_STRICT - added page to nav - added links to new page where appropriate Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * refactor(macros): make JSON_SERIALIZE_ENUM_STRICT use JSON_THROW - added templated wrapper function to fix scope error in calling JSON_THROW Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * refactor(macros): make NLOHMANN_SERIALIZE_ENUM_STRICT use error code 410 - added error code 410 to docs Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * tests(macros): add test for to_json with enum value not mentioned in mapping for NLOHMANN_JSON_SERIALIZE_ENUM_STRICT Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * Apply suggestions from code review Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com> Signed-off-by: Caillin Nugent <nugentcaillin@gmail.com> * fix(macro): prevent compilation error with -Werror and -Wunused-parameter with NLOHMANN_JSON_SERIALIZE_ENUM_STRICT - casted exception to void to avoid warning Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * fix(docs): add link to NLOHMANN_SERIALIZE_ENUM_STRICT docs to exception page Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * docs(macros): add example of exception throwing for NLOHMANN_JSON_SERIALIZE_ENUM_STRICT Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> * refactor(macros): add more in-depth error message to NLOHMANN_JSON_SERIALIZE_ENUM_STRICT - changed error message to follow style of nlohmann/json#4989 - made description of throw wrapper more general - updated tests and example of exceptions Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> --------- Signed-off-by: Caillin Nugent <caillinn@student.unimelb.edu.au> Signed-off-by: Caillin Nugent <nugentcaillin@gmail.com> Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
@@ -1105,7 +1105,7 @@ Just as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above,
|
||||
|
||||
Other Important points:
|
||||
|
||||
- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully.
|
||||
- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully. If you desire an exception in this circumstance use `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT()` which behaves identically except for throwing an exception on unrecognized values.
|
||||
- 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.
|
||||
|
||||
### Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)
|
||||
|
||||
@@ -54,6 +54,7 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
### Enums
|
||||
|
||||
- [**NLOHMANN_JSON_SERIALIZE_ENUM**](nlohmann_json_serialize_enum.md) - serialize/deserialize an enum
|
||||
- [**NLOHMANN_JSON_SERIALIZE_ENUM_STRICT**](nlohmann_json_serialize_enum_strict.md) - serialize/deserialize an enum with exceptions
|
||||
|
||||
### Classes and structs
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ inline void from_json(const BasicJsonType& j, type& e);
|
||||
## See also
|
||||
|
||||
- [Specializing enum conversion](../../features/enum_conversion.md)
|
||||
- [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](./nlohmann_json_serialize_enum_strict.md)
|
||||
- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md)
|
||||
|
||||
## Version history
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
|
||||
|
||||
```cpp
|
||||
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(type, conversion...)
|
||||
```
|
||||
|
||||
By default, enum values are serialized to JSON as integers. In some cases, this could result in undesired behavior. If
|
||||
an enum is modified or re-ordered after data has been serialized to JSON, the later deserialized JSON data may be
|
||||
undefined or a different enum value than was originally intended.
|
||||
|
||||
`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` allows to define a user-defined serialization for every enumerator that
|
||||
throws an exception on undefined input.
|
||||
|
||||
## Parameters
|
||||
|
||||
`type` (in)
|
||||
: name of the enum to serialize/deserialize
|
||||
|
||||
`conversion` (in)
|
||||
: a pair of an enumerator and a JSON serialization; arbitrary pairs can be given as a comma-separated list
|
||||
|
||||
## Default definition
|
||||
|
||||
The macro adds two functions to the namespace which take care of the serialization and deserialization:
|
||||
|
||||
```cpp
|
||||
template<typename BasicJsonType>
|
||||
inline void to_json(BasicJsonType& j, const type& e);
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, type& e);
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
!!! info "Prerequisites"
|
||||
|
||||
The macro must be used inside the namespace of the enum.
|
||||
|
||||
!!! important "Important notes"
|
||||
|
||||
- When using [`get<ENUM_TYPE>()`](../basic_json/get.md), undefined JSON values will throw an exception.
|
||||
- If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the
|
||||
list will be returned when converting to or from JSON. See example 2 below.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example 1: Basic usage"
|
||||
|
||||
The example shows how `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` can be used to serialize/deserialize both classical enums and
|
||||
C++11 enum classes:
|
||||
|
||||
```cpp hl_lines="16 17 18 19 20 21 22 29 30 31 32 33"
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict.output"
|
||||
```
|
||||
|
||||
??? example "Example 2: Multiple conversions for one enumerator"
|
||||
|
||||
The example shows how to use multiple conversions for a single enumerator. In the example, `Color::red` will always
|
||||
be *serialized* to `"red"`, because the first occurring conversion. The second conversion, however, offers an
|
||||
alternative *deserialization* from `"rot"` to `Color::red`.
|
||||
|
||||
```cpp hl_lines="17"
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict_2.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict_2.output"
|
||||
```
|
||||
|
||||
??? example "Example 3: exceptions on invalid serialization"
|
||||
|
||||
The example shows how an invalid serialization causes an exception to be thrown. In the example,
|
||||
Color::unknown is not defined in the mapping used to call `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`
|
||||
so causes an exception when used to serialize. Similarly, "what" does not refer to an enum
|
||||
value so also causes an exception when deserialization is attempted.
|
||||
|
||||
```cpp hl_lines="14 32 33 43 44 45"
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict_err.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
```json
|
||||
--8<-- "examples/nlohmann_json_serialize_enum_strict_err.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Specializing enum conversion](../../features/enum_conversion.md)
|
||||
- [`NLOHMANN_JSON_SERIALIZE_ENUM`](./nlohmann_json_serialize_enum.md)
|
||||
- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md)
|
||||
|
||||
## Version history
|
||||
|
||||
Added in version 3.12.0.
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ns
|
||||
{
|
||||
enum TaskState
|
||||
{
|
||||
TS_STOPPED,
|
||||
TS_RUNNING,
|
||||
TS_COMPLETED,
|
||||
TS_INVALID = -1
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(TaskState,
|
||||
{
|
||||
{ TS_INVALID, nullptr },
|
||||
{ TS_STOPPED, "stopped" },
|
||||
{ TS_RUNNING, "running" },
|
||||
{ TS_COMPLETED, "completed" }
|
||||
})
|
||||
|
||||
enum class Color
|
||||
{
|
||||
red, green, blue, unknown
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(Color,
|
||||
{
|
||||
{ Color::unknown, "unknown" }, { Color::red, "red" },
|
||||
{ Color::green, "green" }, { Color::blue, "blue" }
|
||||
})
|
||||
} // namespace ns
|
||||
|
||||
int main()
|
||||
{
|
||||
// serialization
|
||||
json j_stopped = ns::TS_STOPPED;
|
||||
json j_red = ns::Color::red;
|
||||
std::cout << "ns::TS_STOPPED -> " << j_stopped
|
||||
<< ", ns::Color::red -> " << j_red << std::endl;
|
||||
|
||||
// deserialization
|
||||
json j_running = "running";
|
||||
json j_blue = "blue";
|
||||
auto running = j_running.get<ns::TaskState>();
|
||||
auto blue = j_blue.get<ns::Color>();
|
||||
std::cout << j_running << " -> " << running
|
||||
<< ", " << j_blue << " -> " << static_cast<int>(blue) << std::endl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
ns::TS_STOPPED -> "stopped", ns::Color::red -> "red"
|
||||
"running" -> 1, "blue" -> 2
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ns
|
||||
{
|
||||
enum class Color
|
||||
{
|
||||
red, green, blue, unknown
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(Color,
|
||||
{
|
||||
{ Color::unknown, "unknown" }, { Color::red, "red" },
|
||||
{ Color::green, "green" }, { Color::blue, "blue" },
|
||||
{ Color::red, "rot" } // a second conversion for Color::red
|
||||
})
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// serialization
|
||||
json j_red = ns::Color::red;
|
||||
std::cout << static_cast<int>(ns::Color::red) << " -> " << j_red << std::endl;
|
||||
|
||||
// deserialization
|
||||
json j_rot = "rot";
|
||||
auto rot = j_rot.get<ns::Color>();
|
||||
auto red = j_red.get<ns::Color>();
|
||||
std::cout << j_rot << " -> " << static_cast<int>(rot) << std::endl;
|
||||
std::cout << j_red << " -> " << static_cast<int>(red) << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
0 -> "red"
|
||||
"rot" -> 0
|
||||
"red" -> 0
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ns
|
||||
{
|
||||
|
||||
enum class Color
|
||||
{
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
unknown // not mapped in JSON_SERIALIZE_ENUM_STRICT
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(Color,
|
||||
{
|
||||
{Color::red, "red"},
|
||||
{Color::green, "green"},
|
||||
{Color::blue, "blue"}
|
||||
})
|
||||
|
||||
} // namespace ns
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// invalid serialization
|
||||
try
|
||||
{
|
||||
// ns::color::unknown was not mapped in macro
|
||||
json invalid_serialization = ns::Color::unknown;
|
||||
}
|
||||
catch (const json::exception e)
|
||||
{
|
||||
std::cout << "deserialization failed: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
// invalid deserialization
|
||||
try
|
||||
{
|
||||
// what does not map to an enum
|
||||
json invalid_deserialization("what");
|
||||
ns::Color color = invalid_deserialization.get<ns::Color>();
|
||||
}
|
||||
catch (const json::exception e)
|
||||
{
|
||||
std::cout << "deserialization failed: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
deserialization failed: [json.exception.out_of_range.410] enum value out of range for Color
|
||||
deserialization failed: [json.exception.out_of_range.410] enum value out of range for Color: "what"
|
||||
@@ -55,7 +55,8 @@ Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
|
||||
Other Important points:
|
||||
|
||||
- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this
|
||||
default pair carefully.
|
||||
default pair carefully. If you desire an exception in this circumstance use [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT()`](../api/macros/nlohmann_json_serialize_enum_strict.md)
|
||||
which behaves identically except for throwing an exception on unrecognized values.
|
||||
- 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).
|
||||
|
||||
@@ -868,6 +868,16 @@ Key identifiers to be serialized to BSON cannot contain code point U+0000, since
|
||||
BSON key cannot contain code point U+0000 (at byte 2)
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.410
|
||||
|
||||
Undefined json fields cannot be used with [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](../api/macros/nlohmann_json_serialize_enum_strict.md)
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
enum value out of range
|
||||
```
|
||||
|
||||
## Further exceptions
|
||||
|
||||
This exception is thrown in case of errors that cannot be classified with the
|
||||
|
||||
@@ -294,6 +294,7 @@ nav:
|
||||
- 'NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md
|
||||
- 'NLOHMANN_JSON_NAMESPACE_NO_VERSION': api/macros/nlohmann_json_namespace_no_version.md
|
||||
- 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md
|
||||
- 'NLOHMANN_JSON_SERIALIZE_ENUM_STRICT': api/macros/nlohmann_json_serialize_enum_strict.md
|
||||
- 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md
|
||||
- Community:
|
||||
- community/index.md
|
||||
|
||||
@@ -253,6 +253,61 @@
|
||||
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
@brief function to wrap JSON_THROW_MACRO - there can be compilation errors about
|
||||
there being no arguments to JSON_THROW that depend on template arguments
|
||||
if this is not used to call JSON_THROW
|
||||
*/
|
||||
template<typename ExceptionType>
|
||||
void templated_json_throw(ExceptionType exception)
|
||||
{
|
||||
JSON_THROW(exception);
|
||||
|
||||
/* JSON_THROW(exception) discards exception and aborts - void cast needed to supress
|
||||
compilation error if compiled with -Werror and Wunused-parameter */
|
||||
(void)exception;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief macro to briefly define a mapping between an enum and JSON with exception
|
||||
on invalid input
|
||||
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
|
||||
@since version 3.12.0
|
||||
*/
|
||||
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
|
||||
template<typename BasicJsonType> \
|
||||
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.first == e; \
|
||||
}); \
|
||||
if (it != std::end(m)) j = it->second; \
|
||||
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
||||
} \
|
||||
template<typename BasicJsonType> \
|
||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
if (it != std::end(m)) e = it->first; \
|
||||
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE ": " + j.dump(), &j)); \
|
||||
}
|
||||
|
||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||
// may be removed in the future once the class is split.
|
||||
|
||||
|
||||
@@ -2627,6 +2627,61 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
@brief function to wrap JSON_THROW_MACRO - there can be compilation errors about
|
||||
there being no arguments to JSON_THROW that depend on template arguments
|
||||
if this is not used to call JSON_THROW
|
||||
*/
|
||||
template<typename ExceptionType>
|
||||
void templated_json_throw(ExceptionType exception)
|
||||
{
|
||||
JSON_THROW(exception);
|
||||
|
||||
/* JSON_THROW(exception) discards exception and aborts - void cast needed to supress
|
||||
compilation error if compiled with -Werror and Wunused-parameter */
|
||||
(void)exception;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief macro to briefly define a mapping between an enum and JSON with exception
|
||||
on invalid input
|
||||
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
|
||||
@since version 3.12.0
|
||||
*/
|
||||
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
|
||||
template<typename BasicJsonType> \
|
||||
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.first == e; \
|
||||
}); \
|
||||
if (it != std::end(m)) j = it->second; \
|
||||
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
||||
} \
|
||||
template<typename BasicJsonType> \
|
||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
if (it != std::end(m)) e = it->first; \
|
||||
else templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE ": " + j.dump(), &j)); \
|
||||
}
|
||||
|
||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||
// may be removed in the future once the class is split.
|
||||
|
||||
|
||||
@@ -1657,6 +1657,84 @@ TEST_CASE("JSON to enum mapping")
|
||||
}
|
||||
}
|
||||
|
||||
enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_cards,
|
||||
{
|
||||
{strict_cards::kreuz, "kreuz"},
|
||||
{strict_cards::pik, "pik"},
|
||||
{strict_cards::pik, "puk"}, // second entry for cards::pik; will not be used
|
||||
{strict_cards::herz, "herz"},
|
||||
{strict_cards::karo, "karo"}
|
||||
})
|
||||
|
||||
enum StrictTaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
|
||||
{
|
||||
STRICT_TS_STOPPED,
|
||||
STRICT_TS_RUNNING,
|
||||
STRICT_TS_COMPLETED,
|
||||
STRICT_TS_OTHER, // STRICT_TS_OTHER not in mapping
|
||||
STRICT_TS_INVALID = -1,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(StrictTaskState,
|
||||
{
|
||||
{STRICT_TS_INVALID, nullptr},
|
||||
{STRICT_TS_STOPPED, "stopped"},
|
||||
{STRICT_TS_RUNNING, "running"},
|
||||
{STRICT_TS_COMPLETED, "completed"},
|
||||
})
|
||||
|
||||
TEST_CASE("Strict JSON to enum mapping")
|
||||
{
|
||||
SECTION("enum class")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(strict_cards::kreuz) == "kreuz");
|
||||
CHECK(json(strict_cards::pik) == "pik");
|
||||
CHECK(json(strict_cards::herz) == "herz");
|
||||
CHECK(json(strict_cards::karo) == "karo");
|
||||
|
||||
// json -> enum
|
||||
CHECK(strict_cards::kreuz == json("kreuz"));
|
||||
CHECK(strict_cards::pik == json("pik"));
|
||||
CHECK(strict_cards::herz == json("herz"));
|
||||
CHECK(strict_cards::karo == json("karo"));
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(STRICT_TS_STOPPED) == "stopped");
|
||||
CHECK(json(STRICT_TS_RUNNING) == "running");
|
||||
CHECK(json(STRICT_TS_COMPLETED) == "completed");
|
||||
CHECK(json(STRICT_TS_INVALID) == json());
|
||||
|
||||
// json -> enum
|
||||
CHECK(STRICT_TS_STOPPED == json("stopped"));
|
||||
CHECK(STRICT_TS_RUNNING == json("running"));
|
||||
CHECK(STRICT_TS_COMPLETED == json("completed"));
|
||||
CHECK(STRICT_TS_INVALID == json());
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<StrictTaskState>(), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(STRICT_TS_OTHER), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
TEST_CASE("std::filesystem::path")
|
||||
|
||||
Reference in New Issue
Block a user