()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)
* In function `from_json`, use function [`at()`](../api/basic_json/at.md) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
+* If you control the type, consider defining `to_json`/`from_json` as `friend` functions inside the class ("hidden friends"). Argument-dependent lookup then only finds them for your type, which also avoids a [GCC < 11 compilation error](../home/faq.md#incomplete-detector-type-with-gcc-11).
+??? example "Example: serialize a `person` to JSON with `to_json`"
+
+ ```cpp
+ --8<-- "examples/to_json.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/to_json.output"
+ ```
+
+??? example "Example: deserialize a `person` from JSON with `from_json`"
+
+ ```cpp
+ --8<-- "examples/from_json__default_constructible.cpp"
+ ```
+
+ Output:
+
+ ```
+ --8<-- "examples/from_json__default_constructible.output"
+ ```
## Simplify your life with macros
@@ -98,7 +122,29 @@ There are several macros to make your life easier as long as you want to use a J
For all the macros, the first parameter is the name of the class/struct. The `DERIVED_TYPE` macros require a second parameter of a base class. All the remaining parameters name the member variables. The `WITH_NAMES` macros require a JSON name before each of the variables.
-| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro |
+```mermaid
+flowchart TD
+ A["choosing a NLOHMANN_DEFINE_* macro"] --> B{"adding fields to a base class?"}
+ B -->|"yes"| C["...DERIVED_TYPE..."]
+ B -->|"no"| D["...TYPE..."]
+ C --> E{"need access to private members?"}
+ D --> E
+ E -->|"yes"| F["...INTRUSIVE... (used inside the class)"]
+ E -->|"no"| G["...NON_INTRUSIVE... (used in the namespace)"]
+ F --> H{"only serializing, never parsing back?"}
+ G --> H
+ H -->|"yes"| I["...ONLY_SERIALIZE"]
+ H -->|"no"| J{"allow missing keys when parsing?"}
+ J -->|"yes"| K["...WITH_DEFAULT"]
+ J -->|"no"| L["plain (missing keys throw)"]
+ I --> M{"need custom JSON key names?"}
+ K --> M
+ L --> M
+ M -->|"yes"| N["...WITH_NAMES"]
+ M -->|"no"| O["done"]
+```
+
+| Need access to private members | Need only serialization | Allow missing values when de-serializing | macro |
|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_type_intrusive.md) |
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_intrusive.md) |
@@ -109,7 +155,7 @@ For all the macros, the first parameter is the name of the class/struct. The `DE
For _derived_ classes and structs, use the following macros
-| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro |
+| Need access to private members | Need only serialization | Allow missing values when de-serializing | macro |
|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) |
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) |
@@ -124,7 +170,7 @@ For _derived_ classes and structs, use the following macros
types with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
- For the `WITH_NAMES` variants the limit is halved to 31 member variables.
-??? example
+??? example "Example: using the `NLOHMANN_DEFINE_TYPE_*` macros"
The `to_json`/`from_json` functions for the `person` struct above can be created with:
@@ -245,6 +291,14 @@ For _derived_ classes and structs, use the following macros
This requires a bit more advanced technique. But first, let us see how this conversion mechanism works:
+```mermaid
+flowchart LR
+ A["construct json j = t, or call j.get() for T"] --> B["JSONSerializer for T: to_json / from_json"]
+ B -->|"default JSONSerializer"| C["adl_serializer for T: to_json / from_json"]
+ C -->|"unqualified call, found via ADL"| D["free to_json(j, t) / from_json(j, t) in T's namespace"]
+ B -->|"user specialization replaces the default"| E["user's adl_serializer specialization for T"]
+```
+
The library uses **JSON Serializers** to convert types to JSON.
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).
@@ -300,7 +354,24 @@ NLOHMANN_JSON_NAMESPACE_END
## How can I use `get()` for non-default constructible/non-copyable types?
-There is a way if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
+For a type that is not [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible) but is
+otherwise an ordinary value type, specialize `adl_serializer` with a `from_json` overload that returns the value instead
+of writing into a reference:
+
+??? example "Example: `get()` for a non-default-constructible type"
+
+ ```cpp
+ --8<-- "examples/from_json__non_default_constructible.cpp"
+ ```
+
+ Output:
+
+ ```
+ --8<-- "examples/from_json__non_default_constructible.output"
+ ```
+
+The same technique also works if your type is not copyable, as long as it is
+[MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
```cpp
struct move_only_type {
@@ -359,15 +430,10 @@ json any_to_json(const std::any& a) {
## Why does serializing a `std::map`/`std::unordered_map` with non-string keys produce an array?
-A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map`) is
-serialized as a JSON *array* of 2-element `[key, value]` arrays, not as a JSON object -- JSON object keys must be
-strings, so the library cannot represent an integer-keyed map as an object.
-
-```cpp
-std::map m{{1, "one"}, {2, "two"}};
-json j = m;
-// j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"}
-```
+A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map`) cannot be
+serialized as a JSON object, because JSON object keys must be strings. See
+[Converting maps with non-string keys](types/index.md#converting-maps-with-non-string-keys) in the types article for
+what the library does instead.
## Why does `std::wstring` convert or dump incorrectly?
@@ -411,7 +477,7 @@ struct less_than_32_serializer {
Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention:
```cpp
-template
+template
struct bad_serializer
{
template
@@ -429,3 +495,10 @@ struct bad_serializer
}
};
```
+
+## See also
+
+- [Converting values](conversions.md) - the general overview of `get`/`get_to` and implicit conversions
+- [Specializing enum conversion](enum_conversion.md) - map enums to JSON strings instead of integers
+- [Supported macros](macros.md) - reference for `NLOHMANN_DEFINE_TYPE_*` and related macros
+- [`adl_serializer`](../api/adl_serializer/index.md) - the default `JSONSerializer` used in the conversion dispatch
diff --git a/docs/mkdocs/docs/features/assertions.md b/docs/mkdocs/docs/features/assertions.md
index 789af7989..dadb0bd87 100644
--- a/docs/mkdocs/docs/features/assertions.md
+++ b/docs/mkdocs/docs/features/assertions.md
@@ -16,18 +16,19 @@ before including the `json.hpp` header.
## Function with runtime assertions
-### Unchecked object access to a const value
+### Unchecked access to a const value
-Function [`operator[]`](../api/basic_json/operator%5B%5D.md) implements unchecked access for objects. Whereas a missing
-key is added in the case of non-const objects, accessing a const object with a missing key is undefined behavior (think
-of a dereferenced null pointer) and yields a runtime assertion.
+Function [`operator[]`](../api/basic_json/operator%5B%5D.md) implements unchecked access for arrays and objects. Whereas
+a missing element is added in the case of non-const values, accessing a const value with a missing object key or an
+invalid array index is undefined behavior (think of a dereferenced null pointer) and yields a runtime assertion. This
+also applies to a [JSON pointer](json_pointer.md) that refers to a missing key or an invalid index.
-If you are not sure whether an element in an object exists, use checked access with the
-[`at` function](../api/basic_json/at.md) or call the [`contains` function](../api/basic_json/contains.md) before.
+If you are not sure whether an element exists, use checked access with the [`at` function](../api/basic_json/at.md)
+or call the [`contains` function](../api/basic_json/contains.md) before.
See also the documentation on [element access](element_access/index.md).
-??? example "Example 1: Missing object key"
+??? example "Example: missing object key"
The following code will trigger an assertion at runtime:
@@ -46,7 +47,30 @@ See also the documentation on [element access](element_access/index.md).
Output:
```
- Assertion failed: (m_value.object->find(key) != m_value.object->end()), function operator[], file json.hpp, line 2144.
+ Assertion failed: (it != m_data.m_value.object->end()), function operator[], file json.hpp, line 28795.
+ ```
+
+??? example "Example 2: Invalid array index in a JSON pointer"
+
+ The following code will trigger an assertion at runtime:
+
+ ```cpp
+ #include
+
+ using json = nlohmann::json;
+ using namespace nlohmann::literals;
+
+ int main()
+ {
+ const json j = {{"array", {1, 2, 3}}};
+ auto v = j["/array/5"_json_pointer];
+ }
+ ```
+
+ Output:
+
+ ```
+ Assertion failed: (idx < m_data.m_value.array->size()), function operator[], file json.hpp, line 28758.
```
### Constructing from an uninitialized iterator range
@@ -54,7 +78,7 @@ See also the documentation on [element access](element_access/index.md).
Constructing a JSON value from an iterator range (see [constructor](../api/basic_json/basic_json.md)) with an
uninitialized iterator is undefined behavior and yields a runtime assertion.
-??? example "Example 2: Uninitialized iterator range"
+??? example "Example: uninitialized iterator range"
The following code will trigger an assertion at runtime:
@@ -81,7 +105,7 @@ uninitialized iterator is undefined behavior and yields a runtime assertion.
Any operation on uninitialized iterators (i.e., iterators that are not associated with any JSON value) is undefined
behavior and yields a runtime assertion.
-??? example "Example 3: Uninitialized iterator"
+??? example "Example: uninitialized iterator"
The following code will trigger an assertion at runtime:
@@ -112,7 +136,7 @@ library asserted that the pointer was not `nullptr` using a runtime assertion. I
result in undefined behavior. Since version 3.12.0, this library checks for `nullptr` and throws a
[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) to prevent the undefined behavior.
-??? example "Example 4: Reading from null pointer"
+??? example "Example: reading from null pointer"
The following code will trigger an assertion at runtime:
diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md
index a0c84edaf..3e3d8e885 100644
--- a/docs/mkdocs/docs/features/binary_formats/bjdata.md
+++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md
@@ -61,7 +61,16 @@ The library uses the following mapping from JSON values types to BJData types ac
The following values can **not** be converted to a BJData value:
- - strings with more than 18446744073709551615 bytes, i.e., $2^{64}-1$ bytes (theoretical)
+ - strings with more than 18446744073709551615 bytes, i.e., 264-1 bytes (theoretical)
+
+!!! warning "UTF-8 validation of string values and object keys"
+
+ BJData strings must use UTF-8 encoding. By default (the [`error_handler`](../../api/basic_json/to_bjdata.md)
+ parameter left at `keep`), `to_bjdata()` writes the bytes of string values and object keys unchanged, even if they
+ are not valid UTF-8. With `error_handler_t::strict`, it throws
+ [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8 instead;
+ `replace`/`ignore` sanitize the string. [`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md)
+ makes `strict` the default.
!!! info "Unused BJData markers"
@@ -73,7 +82,7 @@ The library uses the following mapping from JSON values types to BJData types ac
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the
- `dump()` function which serializes NaN or Infinity to `#!json null`.
+ [`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `#!json null`.
!!! info "Endianness"
@@ -163,7 +172,7 @@ The library uses the following mapping from JSON values types to BJData types ac
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array
-??? example
+??? example "Example: serialize JSON values to BJData, with and without size/type optimization"
```cpp
--8<-- "examples/to_bjdata.cpp"
@@ -208,6 +217,19 @@ The library maps BJData types to JSON value types as follows:
The mapping is **complete** in the sense that any BJData value can be converted to a JSON value.
+!!! warning "Ill-formed UTF-8 in string values and object keys"
+
+ BJData strings must use UTF-8 encoding, but checking it on read is opt-in: with the
+ [`error_handler`](../../api/basic_json/from_bjdata.md) parameter left at `keep` (the default), `from_bjdata()`
+ accepts a string value or object key whose bytes are not valid UTF-8 and hands them back unchanged. Passing
+ `error_handler_t::strict` makes `from_bjdata()` check and throw
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) for ill-formed UTF-8, and
+ `replace`/`ignore` sanitize the string instead of keeping it. However,
+ [`dump()`](../../api/basic_json/dump.md) still requires valid UTF-8 and throws
+ [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a value read with the default
+ `keep` handler, unless an error handler is passed that replaces or ignores the ill-formed bytes. `to_bjdata()`'s
+ own `error_handler` parameter defaults to `keep` (see above), so such a value is written back unchanged.
+
!!! info "Round trips"
A value returned by [`from_bjdata`](../../api/basic_json/from_bjdata.md) can be serialized with
@@ -218,7 +240,7 @@ The library maps BJData types to JSON value types as follows:
binary values above), and serializing such an array again may choose different, but equally valid, type markers.
The bytes can then differ, but parsing them again yields the same value.
-??? example
+??? example "Example: deserialize a JSON value from BJData"
```cpp
--8<-- "examples/from_bjdata.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/bon8.md b/docs/mkdocs/docs/features/binary_formats/bon8.md
index 9b5fa1dda..d2d20da19 100644
--- a/docs/mkdocs/docs/features/binary_formats/bon8.md
+++ b/docs/mkdocs/docs/features/binary_formats/bon8.md
@@ -53,8 +53,9 @@ The library uses the following mapping from JSON values types to BON8 types acco
An integer that takes 2 to 4 bytes starts with a UTF-8 lead byte (0xC2..0xF7) that is followed by a byte that cannot
continue a UTF-8 character: 0x00..0x7F for positive and 0xC0..0xFF for negative integers. A string is terminated by
-0xFF only if it is empty, if another string follows it, or if it is the last value of the message; otherwise, the first
-byte of the next value ends it.
+0xFF only if it is empty, if another string follows it, or if nothing follows it in the message; otherwise, the byte
+after it ends it: the first byte of the next value, or the 0xFE that ends an array or object. For example, `["e"]` is
+serialized as 0x81 0x65 0xFF, but `[1,2,3,4,"e"]` as 0x85 0x91 0x92 0x93 0x94 0x65 0xFE.
!!! success "Complete mapping"
@@ -92,7 +93,7 @@ byte of the next value ends it.
- Object keys are written in the order of the object type, which is sorted for `json`, but not for
[`ordered_json`](../../api/ordered_json.md).
-??? example
+??? example "Example: serialize a JSON value to BON8"
```cpp
--8<-- "examples/to_bon8.cpp"
@@ -140,13 +141,13 @@ Non-negative integers are read as number_unsigned, negative integers as number_i
arrays and objects with up to four elements that are terminated by 0xFE, unsorted object keys, or a 0xFF after a
string that would also end without it, are accepted. A second 0xFF is not a terminator but an empty string.
- Strings must be valid UTF-8, and the last string of a message must be terminated by 0xFF.
+ Strings must be valid UTF-8, and a string at the very end of a message must be terminated by 0xFF.
!!! info
Any BON8 output created by `to_bon8` can be successfully parsed by `from_bon8`.
-??? example
+??? example "Example: deserialize a JSON value from BON8"
```cpp
--8<-- "examples/from_bon8.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/bson.md b/docs/mkdocs/docs/features/binary_formats/bson.md
index 6f5603c8c..f205cba17 100644
--- a/docs/mkdocs/docs/features/binary_formats/bson.md
+++ b/docs/mkdocs/docs/features/binary_formats/bson.md
@@ -48,7 +48,7 @@ The library uses the following mapping from JSON values types to BSON types:
As a result, serializing and deserializing a JSON object containing such a value produces a different JSON object,
even though the binary data is unchanged.
-??? example
+??? example "Example: serialize a JSON value to BSON"
```cpp
--8<-- "examples/to_bson.cpp"
@@ -109,16 +109,23 @@ The library maps BSON record types to JSON value types as follows:
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
`from_bson()`.
-!!! warning "UTF-8 validation of string values"
+!!! warning "Ill-formed UTF-8 in string values"
- The BSON specification requires `string` values (type `0x02`) to be valid UTF-8. This library validates the
- bytes of every such string at decode time and rejects ill-formed UTF-8 with a
- [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with `allow_exceptions`
- set to `false`, a discarded value), rather than only failing later when the resulting value is dumped. Element
- (key) names and `binary` values (type `0x05`) are unaffected and are never validated, since they are read
- byte-by-byte as a C string, or are not required to hold text, respectively.
+ The BSON specification requires `string` values (type `0x02`) to be valid UTF-8, but this is not required of a
+ decoder, so checking is opt-in: with the [`error_handler`](../../api/basic_json/from_bson.md) parameter left at
+ `keep` (the default), `from_bson()` accepts a `string` value whose bytes are not valid UTF-8 and hands them back
+ unchanged. Passing `error_handler_t::strict` makes `from_bson()` check and throw
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) for ill-formed UTF-8, and
+ `replace`/`ignore` sanitize the string instead of keeping it. However, [`dump()`](../../api/basic_json/dump.md)
+ still requires valid UTF-8 and throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a
+ value read with the default `keep` handler, unless an error handler is passed that replaces or ignores the
+ ill-formed bytes. `to_bson()`'s own `error_handler` parameter defaults to `keep`, so such a string value or element
+ (key) name is written unchanged; with `strict` (the default if
+ [`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md) is enabled), it throws the same exception
+ instead. Element (key) names are never validated on read, since they are read byte-by-byte as a C string. `binary`
+ values (type `0x05`) are unaffected, since they are not required to hold text.
-??? example
+??? example "Example: deserialize a JSON value from BSON"
```cpp
--8<-- "examples/from_bson.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/cbor.md b/docs/mkdocs/docs/features/binary_formats/cbor.md
index a488466d4..7b5be4631 100644
--- a/docs/mkdocs/docs/features/binary_formats/cbor.md
+++ b/docs/mkdocs/docs/features/binary_formats/cbor.md
@@ -98,7 +98,7 @@ see "binary" cells in the table above.
Binary subtypes will be serialized as tagged items. See [binary values](../binary_values.md#cbor) for an example.
-??? example
+??? example "Example: serialize a JSON value to CBOR"
```cpp
--8<-- "examples/to_cbor.cpp"
@@ -189,21 +189,27 @@ The library maps CBOR types to JSON value types as follows:
([RFC 8392](https://www.rfc-editor.org/rfc/rfc8392.html)), cannot be read with this library and need a
general-purpose CBOR library instead.
-!!! warning "UTF-8 validation of text strings"
+!!! warning "Ill-formed UTF-8 in text strings"
- [RFC 8949, Section 3.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1) requires CBOR text strings
- (major type 3) to be valid UTF-8. This library validates the bytes of every text string (object keys included) at
- decode time and rejects ill-formed UTF-8 with a
- [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with
- `allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting value is
- dumped. Byte strings (major type 2) are unaffected and are never validated, since they are not required to hold
- text.
+ [RFC 8949, Section 3.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1) requires CBOR text strings (major
+ type 3) to be valid UTF-8, but leaves it up to the decoder whether to enforce this, so checking is opt-in: with the
+ [`error_handler`](../../api/basic_json/from_cbor.md) parameter left at `keep` (the default), `from_cbor()` accepts a
+ text string (object keys included) whose bytes are not valid UTF-8 and hands them back unchanged. Passing
+ `error_handler_t::strict` makes `from_cbor()` check and throw
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) for ill-formed UTF-8, and
+ `replace`/`ignore` sanitize the string instead of keeping it. However, [`dump()`](../../api/basic_json/dump.md)
+ still requires valid UTF-8 and throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a
+ value read with the default `keep` handler, unless an error handler is passed that replaces or ignores the
+ ill-formed bytes. `to_cbor()`'s own [`error_handler`](../../api/basic_json/to_cbor.md) parameter defaults to `keep`,
+ so such a value is written back unchanged; with `strict` (the default if
+ [`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md) is enabled), it throws the same exception
+ instead. Byte strings (major type 2) are unaffected, since they are not required to hold text.
!!! warning "Tagged items"
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. Passing `cbor_tag_handler_t::store` to function `from_cbor` stores tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are read as if the tag were ignored. If several tags precede a byte string, only the innermost one is stored. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
-??? example
+??? example "Example: deserialize a JSON value from CBOR"
```cpp
--8<-- "examples/from_cbor.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/messagepack.md b/docs/mkdocs/docs/features/binary_formats/messagepack.md
index 3ce5f7620..24eeab139 100644
--- a/docs/mkdocs/docs/features/binary_formats/messagepack.md
+++ b/docs/mkdocs/docs/features/binary_formats/messagepack.md
@@ -79,7 +79,7 @@ specification:
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
always `false` and caused the float 32 path to be skipped.
-??? example
+??? example "Example: serialize a JSON value to MessagePack"
```cpp
--8<-- "examples/to_msgpack.cpp"
@@ -153,16 +153,25 @@ The library maps MessagePack types to JSON value types as follows:
This applies to the [SAX interface](../parsing/sax_interface.md) as well, as the key is read before it is passed
on. Such input needs a general-purpose MessagePack library instead.
-!!! warning "UTF-8 validation of string values"
+!!! warning "Ill-formed UTF-8 in string values"
- The MessagePack specification requires `str` values (`fixstr`, `str 8`, `str 16`, `str 32`) to be valid UTF-8.
- This library validates the bytes of every such string (object keys included) at decode time and rejects
- ill-formed UTF-8 with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or,
- with `allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting
- value is dumped. `bin`/`ext`/`fixext` values are unaffected and are never validated, since they are not required
- to hold text.
+ The MessagePack specification explicitly allows a `str` value (`fixstr`, `str 8`, `str 16`, `str 32`) to contain
+ a byte sequence that is not valid UTF-8, and expects a deserializer to hand the original bytes back unchanged.
+ This library follows that by default: with its
+ [`error_handler`](../../api/basic_json/from_msgpack.md) parameter left at `keep` (the default),
+ `from_msgpack()` reads `str` bytes (object keys included) as-is, without validating them, so such a value
+ round-trips through `from_msgpack(to_msgpack(j))` byte for byte. Passing `error_handler_t::strict` makes
+ `from_msgpack()` check anyway and throw
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) for ill-formed UTF-8, and
+ `replace`/`ignore` sanitize the string instead of keeping it. `to_msgpack()` also writes `str` bytes as-is by
+ default, since the specification permits it; its [`error_handler`](../../api/basic_json/to_msgpack.md) parameter
+ can be set to `strict` to throw [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) instead, or
+ to `replace`/`ignore` to sanitize the string, for instance for a decoder that rejects ill-formed UTF-8. However,
+ [`dump()`](../../api/basic_json/dump.md) still requires valid UTF-8 and throws
+ [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a value read this way with the
+ default `keep` handler, unless an error handler is passed that replaces or ignores the ill-formed bytes.
-??? example
+??? example "Example: deserialize a JSON value from MessagePack"
```cpp
--8<-- "examples/from_msgpack.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/ubjson.md b/docs/mkdocs/docs/features/binary_formats/ubjson.md
index be545b9fe..f7a14d855 100644
--- a/docs/mkdocs/docs/features/binary_formats/ubjson.md
+++ b/docs/mkdocs/docs/features/binary_formats/ubjson.md
@@ -11,29 +11,29 @@ achieve the generality of JSON, combined with being much easier to process than
The library uses the following mapping from JSON values types to UBJSON types according to the UBJSON specification:
-| JSON value type | value/range | UBJSON type | marker |
-|-----------------|-----------------------------------|----------------|--------|
-| null | `null` | null | `Z` |
-| boolean | `true` | true | `T` |
-| boolean | `false` | false | `F` |
-| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
-| number_integer | -2147483648..-32769 | int32 | `l` |
-| number_integer | -32768..-129 | int16 | `I` |
-| number_integer | -128..127 | int8 | `i` |
-| number_integer | 128..255 | uint8 | `U` |
-| number_integer | 256..32767 | int16 | `I` |
-| number_integer | 32768..2147483647 | int32 | `l` |
-| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
-| number_unsigned | 0..127 | int8 | `i` |
-| number_unsigned | 128..255 | uint8 | `U` |
-| number_unsigned | 256..32767 | int16 | `I` |
-| number_unsigned | 32768..2147483647 | int32 | `l` |
-| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
-| number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` |
-| number_float | *any value* | float64 | `D` |
-| string | *with shortest length indicator* | string | `S` |
-| array | *see notes on optimized format* | array | `[` |
-| object | *see notes on optimized format* | map | `{` |
+| JSON value type | value/range | UBJSON type | marker |
+|-----------------|-------------------------------------------|----------------|--------|
+| null | `null` | null | `Z` |
+| boolean | `true` | true | `T` |
+| boolean | `false` | false | `F` |
+| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
+| number_integer | -2147483648..-32769 | int32 | `l` |
+| number_integer | -32768..-129 | int16 | `I` |
+| number_integer | -128..127 | int8 | `i` |
+| number_integer | 128..255 | uint8 | `U` |
+| number_integer | 256..32767 | int16 | `I` |
+| number_integer | 32768..2147483647 | int32 | `l` |
+| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
+| number_unsigned | 0..127 | int8 | `i` |
+| number_unsigned | 128..255 | uint8 | `U` |
+| number_unsigned | 256..32767 | int16 | `I` |
+| number_unsigned | 32768..2147483647 | int32 | `l` |
+| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
+| number_unsigned | 9223372036854775808..18446744073709551615 | high-precision | `H` |
+| number_float | *any value* | float64 | `D` |
+| string | *with shortest length indicator* | string | `S` |
+| array | *see notes on optimized format* | array | `[` |
+| object | *see notes on optimized format* | map | `{` |
!!! success "Complete mapping"
@@ -47,6 +47,15 @@ The library uses the following mapping from JSON values types to UBJSON types ac
- strings with more than 9223372036854775807 bytes (theoretical)
+!!! warning "UTF-8 validation of string values and object keys"
+
+ UBJSON's required string encoding is UTF-8. By default (the [`error_handler`](../../api/basic_json/to_ubjson.md)
+ parameter left at `keep`), `to_ubjson()` writes the bytes of string values and object keys unchanged, even if they
+ are not valid UTF-8. With `error_handler_t::strict`, it throws
+ [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8 instead;
+ `replace`/`ignore` sanitize the string. [`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md)
+ makes `strict` the default.
+
!!! info "Unused UBJSON markers"
The following markers are not used in the conversion:
@@ -57,7 +66,7 @@ The library uses the following mapping from JSON values types to UBJSON types ac
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the
- `dump()` function which serializes NaN or Infinity to `null`.
+ [`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
!!! info "Optimized formats"
@@ -82,7 +91,7 @@ The library uses the following mapping from JSON values types to UBJSON types ac
documentation. In particular, this means that serialization and the deserialization of a JSON containing binary
values into UBJSON and back will result in a different JSON object.
-??? example
+??? example "Example: serialize JSON values to UBJSON, with and without size/type optimization"
```cpp
--8<-- "examples/to_ubjson.cpp"
@@ -120,7 +129,20 @@ The library maps UBJSON types to JSON value types as follows:
The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value.
-??? example
+!!! warning "Ill-formed UTF-8 in string values and object keys"
+
+ UBJSON's required string encoding is UTF-8, but checking it on read is opt-in: with the
+ [`error_handler`](../../api/basic_json/from_ubjson.md) parameter left at `keep` (the default), `from_ubjson()`
+ accepts a string value or object key whose bytes are not valid UTF-8 and hands them back unchanged. Passing
+ `error_handler_t::strict` makes `from_ubjson()` check and throw
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) for ill-formed UTF-8, and
+ `replace`/`ignore` sanitize the string instead of keeping it. However,
+ [`dump()`](../../api/basic_json/dump.md) still requires valid UTF-8 and throws
+ [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a value read with the default
+ `keep` handler, unless an error handler is passed that replaces or ignores the ill-formed bytes. `to_ubjson()`'s
+ own `error_handler` parameter defaults to `keep` (see above), so such a value is written back unchanged.
+
+??? example "Example: deserialize a JSON value from UBJSON"
```cpp
--8<-- "examples/from_ubjson.cpp"
diff --git a/docs/mkdocs/docs/features/binary_values.md b/docs/mkdocs/docs/features/binary_values.md
index aa3185c2a..98e8e71c3 100644
--- a/docs/mkdocs/docs/features/binary_values.md
+++ b/docs/mkdocs/docs/features/binary_values.md
@@ -27,7 +27,7 @@ vector <|-- binary_t
By default, binary values are stored as `std::vector`. This type can be changed by providing a template
parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as
-`json::binary_t`:
+[`json::binary_t`](../api/basic_json/binary_t.md):
```cpp
auto binary = json::binary_t({0xCA, 0xFE, 0xBA, 0xBE});
@@ -62,21 +62,23 @@ JSON values can be constructed from `json::binary_t`:
json j = binary;
```
-Binary values are primitive values just like numbers or strings:
+Binary values are primitive values just like numbers or strings, as reflected by
+[`is_binary()`](../api/basic_json/is_binary.md) and [`is_primitive()`](../api/basic_json/is_primitive.md):
```cpp
j.is_binary(); // returns true
j.is_primitive(); // returns true
```
-Given a binary JSON value, the `binary_t` can be accessed by reference as via `get_binary()`:
+Given a binary JSON value, the `binary_t` can be accessed by reference via
+[`get_binary()`](../api/basic_json/get_binary.md):
```cpp
j.get_binary().has_subtype(); // returns true
j.get_binary().size(); // returns 4
```
-For convenience, binary JSON values can be constructed via `json::binary`:
+For convenience, binary JSON values can be constructed via [`json::binary`](../api/basic_json/binary.md):
```cpp
auto j2 = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 23);
@@ -99,7 +101,7 @@ JSON does not have a binary type, and this library does not introduce a new type
Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype`
is an integer or `null`.
-??? example
+??? example "Example: serialize a binary value to JSON"
Code:
@@ -133,7 +135,7 @@ is an integer or `null`.
[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes and proposes to serialize binary values
as an array of uint8 values. The library implements this translation.
-??? example
+??? example "Example: serialize a binary value to BJData"
Code:
@@ -192,7 +194,7 @@ as an array of uint8 values. The library implements this translation.
[BON8](binary_formats/bon8.md) neither supports binary values nor subtypes. The library serializes binary values as an
array of integers.
-??? example
+??? example "Example: serialize a binary value to BON8"
Code:
@@ -227,7 +229,7 @@ array of integers.
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as an
unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
-??? example
+??? example "Example: serialize a binary value to BSON"
Code:
@@ -269,7 +271,7 @@ unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00
value will be serialized as byte strings. The library will choose the smallest representation using the length of the
byte array.
-??? example
+??? example "Example: serialize a binary value to CBOR"
Code:
@@ -294,7 +296,9 @@ byte array.
```
Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless
- `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`.
+ `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to
+ [`json::from_cbor`](../api/basic_json/from_cbor.md) (see
+ [`cbor_tag_handler_t`](../api/basic_json/cbor_tag_handler_t.md)).
```json
{
@@ -313,7 +317,7 @@ ext32. The subtype is then added as a signed 8-bit integer.
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
-??? example
+??? example "Example: serialize a binary value to MessagePack"
Code:
@@ -353,7 +357,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes and proposes to serialize binary values
as an array of uint8 values. The library implements this translation.
-??? example
+??? example "Example: serialize a binary value to UBJSON"
Code:
diff --git a/docs/mkdocs/docs/features/comments.md b/docs/mkdocs/docs/features/comments.md
index 95ac72359..86321bc4a 100644
--- a/docs/mkdocs/docs/features/comments.md
+++ b/docs/mkdocs/docs/features/comments.md
@@ -11,7 +11,7 @@ This library does not support comments *by default*. It does so for three reason
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
-However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with `ignore_trailing_commas` (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
+However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with [`ignore_trailing_commas`](trailing_commas.md) (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
diff --git a/docs/mkdocs/docs/features/element_access/checked_access.md b/docs/mkdocs/docs/features/element_access/checked_access.md
index 1fb65e53b..d8dab0104 100644
--- a/docs/mkdocs/docs/features/element_access/checked_access.md
+++ b/docs/mkdocs/docs/features/element_access/checked_access.md
@@ -6,7 +6,7 @@ The [`at`](../../api/basic_json/at.md) member function performs checked access;
desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range)
otherwise.
-??? example "Read access"
+??? example "Example: read access"
Consider the following JSON value:
@@ -31,7 +31,7 @@ otherwise.
The return value is a reference, so it can be used to modify the original value.
-??? example "Write access"
+??? example "Example: write access"
```cpp
j.at("name") = "John Smith";
@@ -50,7 +50,7 @@ The return value is a reference, so it can be used to modify the original value.
When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is
non-existing, an exception is thrown.
-??? example "Accessing via invalid index or missing key"
+??? example "Example: access via invalid index or missing key"
```cpp
j.at("hobbies").at(3) = "cooking";
diff --git a/docs/mkdocs/docs/features/element_access/default_value.md b/docs/mkdocs/docs/features/element_access/default_value.md
index 7b613062b..481448469 100644
--- a/docs/mkdocs/docs/features/element_access/default_value.md
+++ b/docs/mkdocs/docs/features/element_access/default_value.md
@@ -41,9 +41,9 @@ you want to access and a default value in case there is no value stored with tha
The value function is a template, and the return type of the function is determined by the type of the provided
default value unless otherwise specified. This can have unexpected effects. In the example below, we store a 64-bit
- unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator[].md). However,
- when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. This occurs, because `#!c 0`
- has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`.
+ unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator%5B%5D.md).
+ However, when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. This occurs,
+ because `#!c 0` has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`.
To address this issue, either provide a correctly typed default value or use the template parameter to specify the
desired return type. Note that this issue occurs even when a value is stored at the provided key, and the default
diff --git a/docs/mkdocs/docs/features/element_access/index.md b/docs/mkdocs/docs/features/element_access/index.md
index 0b39547ec..262c057b8 100644
--- a/docs/mkdocs/docs/features/element_access/index.md
+++ b/docs/mkdocs/docs/features/element_access/index.md
@@ -5,5 +5,19 @@ There are many ways elements in a JSON value can be accessed:
- unchecked access via [`operator[]`](unchecked_access.md)
- checked access via [`at`](checked_access.md)
- access with default value via [`value`](default_value.md)
-- iterators
-- JSON pointers
+- [iterators](../iterators.md)
+- [JSON pointers](../json_pointer.md)
+
+Testing whether a key or index exists before accessing it is also possible, with
+[`contains`](../../api/basic_json/contains.md) or [`find`](../../api/basic_json/find.md) (which returns an iterator to
+the value, or `end()` if it is not found).
+
+```mermaid
+flowchart TD
+ A["accessing a value"] --> B{"must it exist?"}
+ B -->|"yes, missing is an error"| C["at() -- throws"]
+ B -->|"yes, but checking is my job"| D["operator[] -- unchecked"]
+ B -->|"no, a fallback is fine"| E["value() -- default value"]
+ A --> F{"just testing first?"}
+ F -->|"yes"| G["contains() / find()"]
+```
diff --git a/docs/mkdocs/docs/features/element_access/unchecked_access.md b/docs/mkdocs/docs/features/element_access/unchecked_access.md
index edaaa37a3..7e3f92ba1 100644
--- a/docs/mkdocs/docs/features/element_access/unchecked_access.md
+++ b/docs/mkdocs/docs/features/element_access/unchecked_access.md
@@ -5,7 +5,7 @@
Elements in a JSON object and a JSON array can be accessed via [`operator[]`](../../api/basic_json/operator%5B%5D.md)
similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
-??? example "Read access"
+??? example "Example: read access"
Consider the following JSON value:
@@ -31,7 +31,7 @@ similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a
`#!json null` value is inserted which can immediately be overwritten.
-??? example "Write access"
+??? example "Example: write access"
```cpp
j["name"] = "John Smith";
@@ -52,7 +52,7 @@ The return value is a reference, so it can modify the original value. In case th
When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such
that the passed index is the new maximal index. Intermediate values are filled with `#!json null`.
-??? example "Filling up arrays with `#!json null` values"
+??? example "Example: filling up arrays with `#!json null` values"
```cpp
j["hobbies"][0] = "running";
@@ -94,8 +94,8 @@ that the passed index is the new maximal index. Intermediate values are filled w
- It is **undefined behavior** to access a const object with a non-existing key.
- It is **undefined behavior** to access a const array with an invalid index.
- In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor
- symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). See the documentation
- on [runtime assertions](../assertions.md) for more information.
+ symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../../api/macros/json_assert.md). See the
+ documentation on [runtime assertions](../assertions.md) for more information.
!!! failure "Exceptions"
@@ -105,8 +105,9 @@ that the passed index is the new maximal index. Intermediate values are filled w
## Performance: reserving array capacity
There is no public `reserve(count)` member on `basic_json` for pre-allocating array capacity. If you are building
-a large array incrementally (e.g., via repeated `push_back()`) and know its final size ahead of time, you can
-reserve capacity via `get_ref()` to access the underlying `array_t` directly:
+a large array incrementally (e.g., via repeated [`push_back()`](../../api/basic_json/push_back.md)) and know its final
+size ahead of time, you can reserve capacity via [`get_ref()`](../../api/basic_json/get_ref.md) to access the
+underlying `array_t` directly:
```cpp
json j = json::array();
diff --git a/docs/mkdocs/docs/features/enum_conversion.md b/docs/mkdocs/docs/features/enum_conversion.md
index d75d6e112..3efd8e818 100644
--- a/docs/mkdocs/docs/features/enum_conversion.md
+++ b/docs/mkdocs/docs/features/enum_conversion.md
@@ -29,6 +29,9 @@ The [`NLOHMANN_JSON_SERIALIZE_ENUM()` macro](../api/macros/nlohmann_json_seriali
## Usage
+Serialization converts an enum value to its mapped string, deserialization does the reverse, and an unrecognized JSON
+value deserializes to the first pair in the map:
+
```cpp
// enum to JSON as string
json j = TS_STOPPED;
@@ -43,6 +46,18 @@ json jPi = 3.14;
assert(jPi.get() == TS_INVALID );
```
+??? example "Example: serializing/deserializing enums, including a second enum type"
+
+ ```cpp
+ --8<-- "examples/nlohmann_json_serialize_enum.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/nlohmann_json_serialize_enum.output"
+ ```
+
## Notes
Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
@@ -54,9 +69,25 @@ Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
Other Important points:
-- When using `get()`, 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()`](../api/macros/nlohmann_json_serialize_enum_strict.md)
- which behaves identically except for throwing an exception on unrecognized values.
+- When using [`get()`](../api/basic_json/get.md), 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()`](../api/macros/nlohmann_json_serialize_enum_strict.md) which behaves
+ identically except for throwing an
+ [`out_of_range.410`](../home/exceptions.md#jsonexceptionout_of_range410) exception on unrecognized values, both when
+ serializing an enum value not listed in the map and when deserializing a JSON value that matches none of the map's
+ entries.
- 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).
+
+??? example "Example: `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` throwing on unrecognized values"
+
+ ```cpp
+ --8<-- "examples/nlohmann_json_serialize_enum_strict_err.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/nlohmann_json_serialize_enum_strict_err.output"
+ ```
diff --git a/docs/mkdocs/docs/features/index.md b/docs/mkdocs/docs/features/index.md
index 33403a58c..aaf1253a7 100644
--- a/docs/mkdocs/docs/features/index.md
+++ b/docs/mkdocs/docs/features/index.md
@@ -10,7 +10,8 @@ C++ types, and finally serialize it again.
understand the `#!cpp {}` vs. `#!cpp []` ambiguity.
- [Parsing](parsing/index.md) — read a JSON value from a string, file, or stream, including
[JSON Lines](parsing/json_lines.md), [callbacks](parsing/parser_callbacks.md), the
- [SAX interface](parsing/sax_interface.md), and [error handling](parsing/parse_exceptions.md).
+ [SAX interface](parsing/sax_interface.md), [error handling](parsing/parse_exceptions.md), and
+ [parsing untrusted input](parsing/untrusted_input.md).
- [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar.
## Accessing and modifying values
@@ -43,7 +44,10 @@ C++ types, and finally serialize it again.
- [Types](types/index.md) and [number handling](types/number_handling.md) — how JSON types map to C++ types and how
numbers are treated.
+- [Template parameter requirements](types/template_parameters.md) — what a type passed as one of `basic_json`'s
+ template parameters has to provide.
- [Object order](object_order.md) — keep insertion order with [`ordered_json`](../api/ordered_json.md).
+- [Performance](performance.md) — practical advice on parsing, memory use, serialization, and compile times.
- [Runtime assertions](assertions.md), [supported macros](macros.md), the [`nlohmann` namespace](namespace.md), and
[C++ modules](modules.md) — build-time and runtime configuration.
diff --git a/docs/mkdocs/docs/features/iterators.md b/docs/mkdocs/docs/features/iterators.md
index f45b92fdc..de493dd72 100644
--- a/docs/mkdocs/docs/features/iterators.md
+++ b/docs/mkdocs/docs/features/iterators.md
@@ -4,7 +4,10 @@
A `basic_json` value is a container and allows access via iterators. Depending on the value type, `basic_json` stores zero or more values.
-As for other containers, `begin()` returns an iterator to the first value and `end()` returns an iterator to the value following the last value. The latter iterator is a placeholder and cannot be dereferenced. In case of null values, empty arrays, or empty objects, `begin()` will return `end()`.
+As for other containers, [`begin()`](../api/basic_json/begin.md) returns an iterator to the first value and
+[`end()`](../api/basic_json/end.md) returns an iterator to the value following the last value. The latter iterator is a
+placeholder and cannot be dereferenced. In case of null values, empty arrays, or empty objects, `begin()` will return
+`end()`.

@@ -12,7 +15,7 @@ As for other containers, `begin()` returns an iterator to the first value and `e
When iterating over objects, values are ordered with respect to the `object_comparator_t` type which defaults to `std::less`. See the [types documentation](types/index.md#key-order) for more information.
-??? example
+??? example "Example: iteration order of object values"
```cpp
// create JSON object {"one": 1, "two": 2, "three": 3}
@@ -41,7 +44,7 @@ When iterating over objects, values are ordered with respect to the `object_comp
The JSON iterators have two member functions, `key()` and `value()` to access the object key and stored value, respectively. When calling `key()` on a non-object iterator, an [invalid_iterator.207](../home/exceptions.md#jsonexceptioninvalid_iterator207) exception is thrown.
-??? example
+??? example "Example: access object keys with `key()` and `value()`"
```cpp
// create JSON object {"one": 1, "two": 2, "three": 3}
@@ -76,7 +79,9 @@ for (auto it : j_object)
}
```
-For this reason, the `items()` function allows accessing `iterator::key()` and `iterator::value()` during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator.
+For this reason, the [`items()`](../api/basic_json/items.md) function allows accessing `iterator::key()` and
+`iterator::value()` during range-based for loops. In these loops, a reference to the JSON values is returned, so there
+is no access to the underlying iterator.
```cpp
for (auto& el : j_object.items())
@@ -104,11 +109,12 @@ for (auto& [key, val] : j_object.items())
### Reverse iteration order
-`rbegin()` and `rend()` return iterators in the reverse sequence.
+[`rbegin()`](../api/basic_json/rbegin.md) and [`rend()`](../api/basic_json/rend.md) return iterators in the reverse
+sequence.

-??? example
+??? example "Example: reverse iteration with `rbegin()` and `rend()`"
```cpp
json j = {1, 2, 3, 4};
@@ -132,7 +138,7 @@ for (auto& [key, val] : j_object.items())
Note that "value" means a JSON value in this setting, not values stored in the underlying containers. That is, `*begin()` returns the complete string or binary array and is also safe if the underlying string or binary array is empty.
-??? example
+??? example "Example: iterate over a string value"
```cpp
json j = "Hello, world";
diff --git a/docs/mkdocs/docs/features/json_patch.md b/docs/mkdocs/docs/features/json_patch.md
index 835f07f90..878f0084c 100644
--- a/docs/mkdocs/docs/features/json_patch.md
+++ b/docs/mkdocs/docs/features/json_patch.md
@@ -3,10 +3,17 @@
## Patches
JSON Patch ([RFC 6902](https://tools.ietf.org/html/rfc6902)) defines a JSON document structure for expressing a sequence
-of operations to apply to a JSON document. With the `patch` function, a JSON Patch is applied to the current JSON value
-by executing all operations from the patch.
+of operations to apply to a JSON document. Operations address locations in the document using
+[JSON Pointer](json_pointer.md) paths. With the [`patch`](../api/basic_json/patch.md) function, a JSON Patch is applied
+to the current JSON value by executing all operations from the patch, yielding the patched document as a new value.
-??? example
+!!! tip "Applying a patch without copying"
+
+ [`patch`](../api/basic_json/patch.md) leaves the original value unchanged and returns the patched result as a copy.
+ If the document is large and the original value is no longer needed,
+ [`patch_inplace`](../api/basic_json/patch_inplace.md) applies the same operations in place instead.
+
+??? example "Example: apply a JSON Patch"
The following code shows how a JSON patch is applied to a value.
@@ -22,7 +29,15 @@ by executing all operations from the patch.
## Diff
-The library can also calculate a JSON patch (i.e., a **diff**) given two JSON values.
+The library can also calculate a JSON patch (i.e., a **diff**) given two JSON values with the
+[`diff`](../api/basic_json/diff.md) function.
+
+```mermaid
+flowchart LR
+ S["source"] -->|"diff(source, target)"| P["patch"]
+ S -->|"source.patch(patch)"| T["target"]
+ P -.->|"applied to source, yields"| T
+```
!!! success "Invariant"
@@ -32,7 +47,7 @@ The library can also calculate a JSON patch (i.e., a **diff**) given two JSON va
source.patch(diff(source, target)) == target;
```
-??? example
+??? example "Example: create a JSON Patch from the difference of two values"
The following code shows how a JSON patch is created as a diff for two JSON values.
@@ -45,3 +60,11 @@ The library can also calculate a JSON patch (i.e., a **diff**) given two JSON va
```json
--8<-- "examples/diff.output"
```
+
+## See also
+
+- [JSON Pointer](json_pointer.md) - the addressing scheme used for patch paths
+- [JSON Merge Patch](merge_patch.md) - a simpler, less expressive alternative patch format
+- [`patch`](../api/basic_json/patch.md) - apply a JSON Patch, returning the result as a copy
+- [`patch_inplace`](../api/basic_json/patch_inplace.md) - apply a JSON Patch without copying
+- [`diff`](../api/basic_json/diff.md) - compute a JSON Patch from two values
diff --git a/docs/mkdocs/docs/features/json_pointer.md b/docs/mkdocs/docs/features/json_pointer.md
index c7237c266..786832c96 100644
--- a/docs/mkdocs/docs/features/json_pointer.md
+++ b/docs/mkdocs/docs/features/json_pointer.md
@@ -128,4 +128,5 @@ auto j_original = j_flat.unflatten();
- Class [`json_pointer`](../api/json_pointer/index.md)
- Function [`flatten`](../api/basic_json/flatten.md)
- Function [`unflatten`](../api/basic_json/unflatten.md)
-- [JSON Patch](json_patch.md)
+- [JSON Patch](json_patch.md) - paths inside a patch are JSON Pointers
+- [JSON Merge Patch](merge_patch.md) - an alternative patch format that does not use JSON Pointer
diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md
index e4a628c3e..681980315 100644
--- a/docs/mkdocs/docs/features/macros.md
+++ b/docs/mkdocs/docs/features/macros.md
@@ -83,6 +83,13 @@ When defined, default parse and serialize functions for enums are excluded and h
See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md).
+## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`
+
+When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON
+value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise.
+
+See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md).
+
## `JSON_NO_AUTOMATIC_UDLS`
When defined, `