Skip to content

Commit

Permalink
Add serialization-only user defined type macros (#3816)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeronSix authored Nov 26, 2023
1 parent 5d931c5 commit 360ce45
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;

public:
// No default constructor
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}

friend void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
};
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
class person
{
private:
std::string name = "John Doe";
std::string address = "123 Fake St";
int age = -1;

public:
// No default constructor
person(std::string name_, std::string address_, int age_)
: name(std::move(name_)), address(std::move(address_)), age(age_)
{}

NLOHMANN_DEFINE_TYPE_INTRUSIVE(person, name, address, age)
};
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};

void to_json(nlohmann::json& nlohmann_json_j, const person& nlohmann_json_t)
{
nlohmann_json_j["name"] = nlohmann_json_t.name;
nlohmann_json_j["address"] = nlohmann_json_t.address;
nlohmann_json_j["age"] = nlohmann_json_t.age;
}
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

namespace ns
{
struct person
{
std::string name;
std::string address;
int age;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(person, name, address, age)
} // namespace ns

int main()
{
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// serialization: person -> json
json j = p;
std::cout << "serialization: " << j << std::endl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
serialization: {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
6 changes: 4 additions & 2 deletions docs/mkdocs/docs/api/macros/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ header. See also the [macro overview page](../../features/macros.md).

## Serialization/deserialization macros

- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)**<br>**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)**][DefInt]
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)**<br>**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)**
<br>**NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, member...)**][DefInt]
\- serialization/deserialization of types _with_ access to private variables
- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)**<br>**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)**][DefNonInt]
- [**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)**<br>**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)**
<br>**NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, member...)**][DefNonInt]
\- serialization/deserialization of types _without_ access to private variables
- [**NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)**](nlohmann_json_serialize_enum.md) - serialization/deserialization of enum types

Expand Down
40 changes: 35 additions & 5 deletions docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
# NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE

```cpp
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...) // (1)
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...) // (2)
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, member...) // (3)
```
These macros can be used to simplify the serialization/deserialization of types if you want to use a JSON object as
Expand All @@ -16,6 +17,7 @@ parameter is the name of the class/struct, and all remaining parameters name the
2. Will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the
respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function
default constructs an object and uses its values as the defaults when calling the `value` function.
3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization in required.
## Parameters
Expand All @@ -31,7 +33,7 @@ The macros add two friend functions to the class which take care of the serializ
```cpp
friend void to_json(nlohmann::json&, const type&);
friend void from_json(const nlohmann::json&, type&);
friend void from_json(const nlohmann::json&, type&); // except (3)
```

See examples below for the concrete generated code.
Expand All @@ -40,7 +42,7 @@ See examples below for the concrete generated code.

!!! info "Prerequisites"

1. The type `type` must be default constructible. See [How can I use `get()` for non-default
1. The type `type` must be default constructible (except (3)). See [How can I use `get()` for non-default
constructible/non-copyable types?][GetNonDefNonCopy] for how to overcome this limitation.
2. The macro must be used inside the type (class/struct).

Expand Down Expand Up @@ -108,19 +110,47 @@ See examples below for the concrete generated code.

The macro is equivalent to:

```cpp hl_lines="21 22 23 24 25 26 27 28 29 30 31 32 33 34 35"
```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35"
--8<-- "examples/nlohmann_define_type_intrusive_with_default_explicit.cpp"
```

Note how a default-initialized `person` object is used in the `from_json` to fill missing values.

??? example "Example (3): NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE"
Consider the following complete example:

```cpp hl_lines="22"
--8<-- "examples/nlohmann_define_type_intrusive_only_serialize_macro.cpp"
```

Output:

```json
--8<-- "examples/nlohmann_define_type_intrusive_only_serialize_macro.output"
```

Notes:

- `ns::person` is non-default-constructible. This allows this macro to be used instead of
`NLOHMANN_DEFINE_TYPE_INTRUSIVE` and `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT`.
- `ns::person` has private member variables. This makes `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE` applicable, but not
`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE`.
- The macro `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE` is used _inside_ the class.

The macro is equivalent to:

```cpp hl_lines="22 22 23 24 25 26 27"
--8<-- "examples/nlohmann_define_type_intrusive_only_serialize_explicit.cpp"
```

## See also

- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE / NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_non_intrusive.md)
- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE{_WITH_DEFAULT, _ONLY_SERIALIZE}](nlohmann_define_type_non_intrusive.md)
for a similar macro that can be defined _outside_ the type.
- [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview.

## Version history

1. Added in version 3.9.0.
2. Added in version 3.11.0.
3. Added in version TODO.
42 changes: 36 additions & 6 deletions docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
# NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE

```cpp
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...) // (1)
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...) // (2)
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, member...) // (3)
```
These macros can be used to simplify the serialization/deserialization of types if you want to use a JSON object as
Expand All @@ -16,6 +17,7 @@ parameter is the name of the class/struct, and all remaining parameters name the
2. Will use [`value`](../basic_json/value.md) during deserialization and fall back to the default value for the
respective type of the member variable if a key in the JSON object is missing. The generated `from_json()` function
default constructs an object and uses its values as the defaults when calling the `value` function.
3. Only defines the serialization. Useful in cases when the type does not have a default constructor and only serialization in required.
## Parameters
Expand All @@ -31,7 +33,7 @@ The macros add two functions to the namespace which take care of the serializati
```cpp
void to_json(nlohmann::json&, const type&);
void from_json(const nlohmann::json&, type&);
void from_json(const nlohmann::json&, type&); // except (3)
```

See examples below for the concrete generated code.
Expand All @@ -40,7 +42,7 @@ See examples below for the concrete generated code.

!!! info "Prerequisites"

1. The type `type` must be default constructible. See [How can I use `get()` for non-default constructible/non-copyable types?][GetNonDefNonCopy]
1. The type `type` must be default constructible (except (3). See [How can I use `get()` for non-default constructible/non-copyable types?][GetNonDefNonCopy]
for how to overcome this limitation.
2. The macro must be used outside the type (class/struct).
3. The passed members must be public.
Expand Down Expand Up @@ -88,7 +90,7 @@ See examples below for the concrete generated code.

Consider the following complete example:

```cpp hl_lines="21"
```cpp hl_lines="22"
--8<-- "examples/nlohmann_define_type_non_intrusive_with_default_macro.cpp"
```

Expand All @@ -109,19 +111,47 @@ See examples below for the concrete generated code.

The macro is equivalent to:

```cpp hl_lines="21 22 23 24 25 26 27 28 29 30 31 32 33 34"
```cpp hl_lines="22 23 24 25 26 27 28 29 30 31 32 33 34 35"
--8<-- "examples/nlohmann_define_type_non_intrusive_with_default_explicit.cpp"
```

Note how a default-initialized `person` object is used in the `from_json` to fill missing values.

??? example "Example (3): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE"

Consider the following complete example:

```cpp hl_lines="16"
--8<-- "examples/nlohmann_define_type_non_intrusive_only_serialize_macro.cpp"
```

Output:

```json
--8<-- "examples/nlohmann_define_type_non_intrusive_only_serialize_macro.output"
```

Notes:

- `ns::person` is non-default-constructible. This allows this macro to be used instead of
`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` and `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`.
- `ns::person` has only public member variables. This makes `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE` applicable.
- The macro `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE` is used _outside_ the class, but _inside_ its namespace `ns`.

The macro is equivalent to:

```cpp hl_lines="16 17 18 19 20 21"
--8<-- "examples/nlohmann_define_type_non_intrusive_only_serialize_explicit.cpp"
```

## See also

- [NLOHMANN_DEFINE_TYPE_INTRUSIVE / NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT](nlohmann_define_type_intrusive.md)
- [NLOHMANN_DEFINE_TYPE_INTRUSIVE{_WITH_DEFAULT, _ONLY_SERIALIZE}](nlohmann_define_type_intrusive.md)
for a similar macro that can be defined _inside_ the type.
- [Arbitrary Type Conversions](../../features/arbitrary_types.md) for an overview.

## Version history

1. Added in version 3.9.0.
2. Added in version 3.11.0.
3. Added in version TODO.
14 changes: 14 additions & 0 deletions docs/mkdocs/docs/features/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ an object and uses its values as the defaults when calling the [`value`](../api/

See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_intrusive.md).

## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(type, member...)`

This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE` except that it defines only the serialization code. This is
useful when the user type does not have a default constructor and only the serialization is required.

See [full documentation of `NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE`](../api/macros//nlohmann_define_type_intrusive.md).

## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)`

This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as
Expand All @@ -138,6 +145,13 @@ an object and uses its values as the defaults when calling the [`value`](../api/

See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT`](../api/macros/nlohmann_define_type_non_intrusive.md).

## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(type, member...)`

This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` except that it defines only the serialization code. This is
useful when the user type does not have a default constructor and only the serialization is required.

See [full documentation of `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE`](../api/macros//nlohmann_define_type_non_intrusive.md).

## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)`

This macro simplifies the serialization/deserialization of enum types. See
Expand Down
6 changes: 6 additions & 0 deletions include/nlohmann/detail/macro_scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }

#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }

/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
Expand All @@ -415,6 +418,9 @@
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }

#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
Expand Down
Loading

0 comments on commit 360ce45

Please sign in to comment.