Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/externals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ struct bad_alloc {};
/// @see https://en.cppreference.com/w/cpp/container/map
struct map {};

/// !EXTERNAL!
///
/// @see https://en.cppreference.com/cpp/utility/variant/monostate
struct monostate {};

/// !EXTERNAL!
///
/// @see https://en.cppreference.com/w/cpp/container/multimap
struct multimap {};

/// !EXTERNAL!
///
/// @see https://en.cppreference.com/w/cpp/container/unordered_map
Expand Down
15 changes: 7 additions & 8 deletions doc/pages/conversion/context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Previously in this section we've been assuming that there is a particular
fitting JSON representation for a type. But this is not always the case. Often
one needs to represent particular value with JSON of certain format in one
situation and with another format in a different situation. This can be
achieved with Boost.JSON by providing an extra argument---context.
achieved with Boost.JSON by providing an extra argument--context.

Let's implement conversion from `user_ns::ip_address` to a JSON string:

Expand Down Expand Up @@ -125,13 +125,12 @@ contexts to conversions of nested objects. And in the case when you want to
provide your own conversion function for a composite type enabled by a
particular context, you usually also need to do that.

Consider this example. As was discussed in a previous section,
<<ref_is_map_like>> requires that your key type satisfies
<<ref_is_string_like>>. Now, let's say your keys are not string-like, but they
do convert to <<ref_string>>. You can make such maps to also convert to objects
using a context. But if you want to also use another context for values, you
need a way to pass the full combined context to map elements. So, you want the
following test to succeed.
Consider this example. <<ref_map_category>> requires that your key type is of
<<ref_string_category>>. Now, let's say your keys' category is different but
they do convert to <<ref_string>>. You can make such maps to also convert to
objects using a context. But if you want to also use another context for
values, you need a way to pass the full combined context to map elements. So,
you want the following test to succeed.

[source]
----
Expand Down
37 changes: 21 additions & 16 deletions doc/pages/conversion/custom.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ Official repository: https://github.com/boostorg/json

= Custom Conversions
Boost.JSON uses two mechanisms to customize conversion between <<ref_value>>
and user types. One mechanism involves specializing type traits. The other one
is more powerful and requires defining overloads of `tag_invoke`. Both
mechanisms will be further explained in this section.

== Conversion Traits
Previously a number of conversion type traits, like <<ref_is_tuple_like>> or
<<ref_is_sequence_like>>, were introduced. The library tries the traits one
after another and uses the implementation that corresponds to the first
matching trait. In some cases, though, a type would match a trait with a higher
priority, but the user intends for it to belong to a lower priority category.
If this happens the user can specialize the trait that's not supposed to match
for that type to be an equivalent of `std::false_type`.
and user types. One mechanism involves specializing <<ref_use_category>>. The
other one is more powerful and requires defining overloads of `tag_invoke`.
Both mechanisms will be further explained in this section.

== `use_category`

The library generally deduces the appropriate implementation of conversion for
a given type using internal type traits. These type traits attempt to deduce
the correct conversion category by checking if the type satisfies the
requirements associated with that category. The categories are checked one by
one, in the order of their appearance in the table in the previous subsection,
and the first one whose requirements are satisfied is selected.

In some cases, though, a type would match a category with a higher priority,
but the user intends for it to belong to a lower priority category. If this
happens the user can specialize the template `use_category` for that type to be
equivalent to the intended category.

Consider this type:

Expand All @@ -33,9 +38,9 @@ It exposes both a sequence API and a tuple API. But converting from
<<ref_value>> to `user_ns::ip_address` would not be able to use implementation
for sequences, since those are constructed empty and then populated one element
at a time, while `ip_address` has a fixed size of 4. The tuple conversion would
fit, though. The only problem is that <<ref_is_tuple_like>> has a lower
priority than <<ref_is_sequence_like>>. In order to circumvent this, the user
only needs to specialize <<ref_is_sequence_like>> to not match `ip_address`.
fit, though. The only problem is that `tuple_category` has a lower priority
than `sequence_category`. In order to circumvent this, the user only needs to
specialize `use_category` for `ip_address`.

[source]
----
Expand Down Expand Up @@ -84,7 +89,7 @@ include::../../../test/snippets.cpp[tag=snippet_tag_invoke_1,indent=0]
----

Since the type being converted is embedded into the function's signature,
user-provided overloads are visible to argument-dependent lookup and will be
user-provided overloads are visible to argument-dependent lookup and become
candidates when a conversion is performed:

[source]
Expand Down
2 changes: 1 addition & 1 deletion doc/pages/conversion/direct.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The drawback of this approach is that fully custom type representations are
not supported, only the library-provided conversions are. Also all objects that
should be populated by parsing have to be default constructible types. This
includes not only the top-level object, but e.g. elements of containers,
members of described `struct`s, and alternatives of variants.
members of described ``struct``s, and alternatives of variants.

That being said, if your types are default-constructible and you don't need the
customisability allowed by <<ref_value_to>> and <<ref_value_from>>, then you
Expand Down
2 changes: 1 addition & 1 deletion doc/pages/conversion/nothrow.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ it supports with <<ref_value_to>>. If a user wants to use it with custom types,
an overload of `tag_invoke` of this form needs to be provided:

```
result_for<T, value>::type
boost::system::result<T>
tag_invoke( const try_value_to_tag< T >&, const value& );
```

Expand Down
70 changes: 33 additions & 37 deletions doc/pages/conversion/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,28 @@ While the <<ref_value>> container makes it easy to create ad-hoc structures,
often it is necessary to convert between JSON and user-defined types or types
from the standard library.

The function template <<ref_value_from>> provides an interface to construct
a <<ref_value>> from a type `T`. The function template <<ref_value_to>>
converts in the opposite direction, from a type `T` to <<ref_value>>. Both
support a wide variety of different
Boost.JSON provides several components to achieve this. For example, the
function template <<ref_value_from>> provides an interface to construct
a <<ref_value>> from a type `T`, and the function template <<ref_value_to>>
converts in the opposite direction, from a type `T` to <<ref_value>>. These
components support a wide variety of different
https://en.cppreference.com/w/cpp/language/types[fundamental types], such as
`int` or `double`, standard library types, such as `std::string` or
`std::vector<T>`, and can be extended to support user-defined types.
`int` or `double`, standard library types, such as {std_string} or
{std_vector}, and can be extended to support user-defined types.

[source]
----
include::../../../test/snippets.cpp[tag=snippet_conv_1,indent=0]
----

For the type `T`, the appropriate conversion approach is chosen from the
following list of categories. The first matching category is selected.
For a type `T` the library chooses a conversion implementation that corresponds
to the first matching category from the following list.

.Conversion categories
[%autowidth,cols=4]
|===
|Category of T|Comment|`value_from` behavior|`value_to` behavior

|Custom conversion.
|
|Custom behavior.
|Custom behavior.

|Boost.JSON container.
|
|The result is equal to the input value.
Expand All @@ -55,66 +51,66 @@ following list of categories. The first matching category is selected.
|
a| The result is a number equal to input and has the type

* `std::int64_t`, if `T` is a signed integer'; or
* `std::int64_t`, if `T` is a signed integer; or
* `std::uint64_t`, if `T` is an unsigned integer; or
* `double` otherwise.
|The result is created via <<ref_value_to_number>>.

|Type satisfying <<ref_is_null_like>>
|<<ref_null_category>>
|Intended for types like {std_monostate}.
|The result is a null value.
|The result is default-constructed.

|Type satisfying <<ref_is_string_like>>.
|A sequence of `char`s, e.g. `std::string`.
|<<ref_string_category>>
|A sequence of ``char``s, e.g. {std_string}.
|The result is a <<ref_string>>.
|The result is constructed from a <<ref_string_view>>.

|Type satisfying <<ref_is_variant_like>>.
|`std::variant` and similar types, e.g. `boost::variant2::variant`.
|<<ref_variant_category>>
|{std_variant} and similar types, e.g. {ref_variant}.
|The result is equal to the result of conversion of the active variant
alternative.
|The result holds the first alternative for which a conversion succeeds.

|Type satisfying <<ref_is_optional_like>>
|
|<<ref_optional_category>>
|{std_optional} and similar types, e.g. {ref_optional}.
|If the input value is empty, the result is a `null`. Otherwise it is
equivalent to conversion of the object stored inside of optional.
|The result is default constructed if the input value is `null`. Otherwise the
result is constructed from the result of conversion of the input to the
type stored in optional.

|Type satisfying <<ref_is_map_like>>.
|A one-to-one mapping (e.g. `std::map`) with string-like keys.
|<<ref_map_category>>
|A one-to-one mapping (e.g. {std_map}) with string-like keys.
|The result is an <<ref_object>>.
|The result is default-constructed, and elements are `insert`-ed at the end.

|Type satisfying <<ref_is_sequence_like>>.
|A sequence of elements, e.g. `std::vector`.
|<<ref_sequence_category>>
|A sequence of elements, e.g. {std_vector}.
|The result is an <<ref_array>>.
|The result is default-constructed, and elements are `insert`-ed at the end.

|Type satisfying <<ref_is_tuple_like>>.
|A heterogenous sequence with fixed size, e.g. `std::tuple` and `std::pair`.
|<<ref_tuple_category>>
|A heterogenous sequence with fixed size, e.g. {std_tuple} and {std_pair}.
|The result is an <<ref_array>>.
|The result is constructed with the array elements as constructor arguments.

|Type satisfying <<ref_is_described_class>>
|<<ref_described_class_category>>
|
|The result is an <<ref_object>> with described members' names as keys.
|The result is default-constructed and described members are assigned
corresponding values.

|Type satisfying <<ref_is_described_enum>>
|<<ref_described_enum_category>>
|
|If the input value is equal to one of the described enumerators, the result is
a <<ref_string>>, containing its name. Otherwise it's equal to the input
value converted to its underlying type.
|The result is the described enumerator, corresponding to the input
<<ref_string>>.

|Type satisfying <<ref_is_path_like>>.
|`std::filesystem::path` and similar types, e.g. `boost::filesystem::path`.
|<<ref_path_category>>
|{std_path} and similar types, e.g. {ref_path}.
|The result is equal to the result of `path::generic_string`.
|The result is constructed from two pointers to `const char`.
|===
Expand All @@ -127,11 +123,11 @@ contained objects is applied recursively. For example:
include::../../../test/snippets.cpp[tag=snippet_conv_recursive,indent=0]
----

Here, the map is converted into an <<ref_object>>, since it matches
<<ref_is_map_like>>. Each of its keys is converted into a <<ref_string>>, as
`std::string` matches <<ref_is_string_like>>, and each of its values is
converted into an <<ref_array>>, as `std::pair` matches <<ref_is_tuple_like>>.
Finally, elements of pairs are converted into a `std::int64_t` number and
Here, the map is converted to an <<ref_object>>, since its conversion category
is <<ref_map_category>>. Each of its keys is converted into a <<ref_string>>,
as `std::string` is of <<ref_string_category>>, and each of its values is
converted into an <<ref_array>>, as `std::pair` is of <<ref_tuple_category>>.
Finally, elements of pairs are converted to a `std::int64_t` number and
a `bool`.

:leveloffset: +1
Expand All @@ -140,8 +136,8 @@ include::custom.adoc[]
include::nothrow.adoc[]
include::alloc.adoc[]
include::context.adoc[]
include::forward.adoc[]
include::direct.adoc[]
include::forward.adoc[]
include::guidelines.adoc[]

:leveloffset: -1
8 changes: 8 additions & 0 deletions doc/pages/definitions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ Official repository: https://github.com/boostorg/json
:ref_error_category: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_category[`error_category`]]
:ref_error_code: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_code[`error_code`]]
:ref_error_condition: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_condition[`error_condition`]]
:ref_optional: pass:q[https://www.boost.org/doc/libs/latest/libs/optional/doc/html/boost_optional/reference/header__boost_optional_optional_hpp_/header_optional_optional_values.html#reference_operator_template[`boost::optional`]]
:ref_path: pass:q[https://www.boost.org/doc/libs/latest/libs/filesystem/doc/reference.html#class-path[`boost::filesystem::path`]]
:ref_result: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_resultt_e[`result`]]
:ref_system_error: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_system_error[`system_error`]]
:ref_variant: pass:q[https://www.boost.org/doc/libs/latest/libs/variant2/doc/html/variant2.html#ref_variant[`boost::variant2::variant`]]

:req_Allocator: pass:q[https://en.cppreference.com/w/cpp/named_req/Allocator[__Allocator__]]
:req_CopyAssignable: pass:q[https://en.cppreference.com/w/cpp/named_req/CopyAssignable[__CopyAssignable__]]
Expand All @@ -33,12 +36,17 @@ Official repository: https://github.com/boostorg/json
:std_initializer_list: pass:q[https://en.cppreference.com/w/cpp/utility/initializer_list[`std::initializer_list`]]
:std_complex: pass:q[https://en.cppreference.com/w/cpp/numeric/complex[`std::complex`]]
:std_hash: pass:q[https://en.cppreference.com/w/cpp/utility/hash[`std::hash`]]
:std_map: pass:q[https://en.cppreference.com/w/cpp/container/map[`std::map`]]
:std_memory_resource: pass:q[https://en.cppreference.com/w/cpp/memory/memory_resource[`std::pmr::memory_resource`]]
:std_monostate: pass:q[https://en.cppreference.com/w/cpp/utility/variant/monostate[`std::monostate`]]
:std_optional: pass:q[https://en.cppreference.com/w/cpp/utility/optional[`std::optional`]]
:std_ostream: pass:q[https://en.cppreference.com/w/cpp/io/basic_ostream[`std::ostream`]]
:std_pair: pass:q[https://en.cppreference.com/w/cpp/utility/pair[`std::pair`]]
:std_path: pass:q[https://en.cppreference.com/w/cpp/filesystem/path[`std::filesystem::path`]]
:std_polymorphic_allocator: pass:q[https://en.cppreference.com/w/cpp/memory/polymorphic_allocator[`std::pmr::polymorphic_allocator`]]
:std_string: pass:q[https://en.cppreference.com/w/cpp/string/basic_string[`std::string`]]
:std_unordered_map: pass:q[https://en.cppreference.com/w/cpp/container/unordered_map[`std::unordered_map`]]
:std_uses_allocator: pass:q[https://en.cppreference.com/w/cpp/memory/uses_allocator[`std::uses_allocator`]]
:std_variant: pass:q[https://en.cppreference.com/w/cpp/utility/variant[`std::variant`]]
:std_vector: pass:q[https://en.cppreference.com/w/cpp/container/vector[`std::vector`]]
:std_tuple: pass:q[https://en.cppreference.com/w/cpp/utility/tuple[`std::tuple`]]
48 changes: 34 additions & 14 deletions doc/pages/reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ a| *Classes* +
<<ref_value_ref>> +
<<ref_value_stack>>

*Aliases* +
<<ref_parser_for>> +
<<ref_string_view>>

a| *Functions* +
<<ref_get>> +
<<ref_get_null_resource>> +
Expand All @@ -52,7 +56,7 @@ a| *Functions* +
<<ref_pilfered>> +
<<ref_is_pilfer_constructible>>

| *Operators* +
a| *Operators* +
<<ref_operator_eq_eq>> +
<<ref_operator_not_eq>> +
<<ref_operator_gt>> +
Expand All @@ -61,37 +65,53 @@ a| *Functions* +
<<ref_operator_lt_eq>> +
<<ref_operator_lt_lt>> +

*Aliases* +
<<ref_parser_for>> +
<<ref_string_view>>

*Constants* +
<<ref_array_kind>> +
<<ref_condition>> +
<<ref_conversion_category>> +
<<ref_error>> +
<<ref_kind>> +
<<ref_number_precision>> +
<<ref_object_kind>> +
<<ref_string_kind>>

| *Type Traits* +
a| *Type Traits* +
<<ref_described_class_category>> +
<<ref_described_enum_category>> +
<<ref_has_value_from>> +
<<ref_has_value_to>> +
<<ref_is_deallocate_trivial>> +
<<ref_map_category>> +
<<ref_null_category>> +
<<ref_optional_category>> +
<<ref_path_category>> +
<<ref_result_for>> +
<<ref_sequence_category>> +
<<ref_string_category>> +
<<ref_try_value_to_tag>> +
<<ref_tuple_category>> +
<<ref_use_category>> +
<<ref_value_from_tag>> +
<<ref_value_to_tag>> +
<<ref_variant_category>> +
<<ref_unknown_category>>

4+h|Deprecated

a|
<<ref_is_described_class>> +
<<ref_is_described_enum>> +
<<ref_is_map_like>> +
<<ref_is_map_like>>
a|
<<ref_is_null_like>> +
<<ref_is_optional_like>> +
<<ref_is_optional_like>>
a|
<<ref_is_path_like>> +
<<ref_is_sequence_like>> +
<<ref_is_string_like>> +
<<ref_is_string_like>>
a|
<<ref_is_tuple_like>> +
<<ref_is_variant_like>> +
<<ref_result_for>> +
<<ref_try_value_to_tag>> +
<<ref_value_from_tag>> +
<<ref_value_to_tag>>
<<ref_is_variant_like>>

|===

Expand Down
Loading
Loading