Skip to content

Commit 3436676

Browse files
committed
refactor conversion category customisation
Users are now meant to specialise use_category.
1 parent 9e0d94d commit 3436676

19 files changed

Lines changed: 884 additions & 303 deletions

doc/externals.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,16 @@ struct bad_alloc {};
212212
/// @see https://en.cppreference.com/w/cpp/container/map
213213
struct map {};
214214

215+
/// !EXTERNAL!
216+
///
217+
/// @see https://en.cppreference.com/cpp/utility/variant/monostate
218+
struct monostate {};
219+
220+
/// !EXTERNAL!
221+
///
222+
/// @see https://en.cppreference.com/w/cpp/container/multimap
223+
struct multimap {};
224+
215225
/// !EXTERNAL!
216226
///
217227
/// @see https://en.cppreference.com/w/cpp/container/unordered_map

doc/pages/conversion/context.adoc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Previously in this section we've been assuming that there is a particular
1212
fitting JSON representation for a type. But this is not always the case. Often
1313
one needs to represent particular value with JSON of certain format in one
1414
situation and with another format in a different situation. This can be
15-
achieved with Boost.JSON by providing an extra argument---context.
15+
achieved with Boost.JSON by providing an extra argument--context.
1616

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

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

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

136135
[source]
137136
----

doc/pages/conversion/custom.adoc

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@ Official repository: https://github.com/boostorg/json
99

1010
= Custom Conversions
1111
Boost.JSON uses two mechanisms to customize conversion between <<ref_value>>
12-
and user types. One mechanism involves specializing type traits. The other one
13-
is more powerful and requires defining overloads of `tag_invoke`. Both
14-
mechanisms will be further explained in this section.
15-
16-
== Conversion Traits
17-
Previously a number of conversion type traits, like <<ref_is_tuple_like>> or
18-
<<ref_is_sequence_like>>, were introduced. The library tries the traits one
19-
after another and uses the implementation that corresponds to the first
20-
matching trait. In some cases, though, a type would match a trait with a higher
21-
priority, but the user intends for it to belong to a lower priority category.
22-
If this happens the user can specialize the trait that's not supposed to match
23-
for that type to be an equivalent of `std::false_type`.
12+
and user types. One mechanism involves specializing <<ref_use_category>>. The
13+
other one is more powerful and requires defining overloads of `tag_invoke`.
14+
Both mechanisms will be further explained in this section.
15+
16+
== `use_category`
17+
18+
The library generally deduces the appropriate implementation of conversion for
19+
a given type using internal type traits. These type traits attempt to deduce
20+
the correct conversion category by checking if the type satisfies the
21+
requirements associated with that category. The categories are checked one by
22+
one, in the order of their appearance in the table in the previous subsection,
23+
and the first one whose requirements are satisfied is selected.
24+
25+
In some cases, though, a type would match a category with a higher priority,
26+
but the user intends for it to belong to a lower priority category. If this
27+
happens the user can specialize the template `use_category` for that type to be
28+
equivalent to the intended category.
2429

2530
Consider this type:
2631

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

4045
[source]
4146
----
@@ -84,7 +89,7 @@ include::../../../test/snippets.cpp[tag=snippet_tag_invoke_1,indent=0]
8489
----
8590

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

9095
[source]

doc/pages/conversion/overview.adoc

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ https://en.cppreference.com/w/cpp/language/types[fundamental types], such as
2828
include::../../../test/snippets.cpp[tag=snippet_conv_1,indent=0]
2929
----
3030

31-
For the type `T`, the appropriate conversion approach is chosen from the
32-
following list of categories. The first matching category is selected.
31+
For the type `T`, the appropriate conversion approach is the first matching
32+
category from the following list.
3333

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

39-
|Custom conversion.
40-
|
39+
|Custom conversion
40+
|Uses `tag_invoke` overload.
4141
|Custom behavior.
4242
|Custom behavior.
4343

@@ -55,66 +55,66 @@ following list of categories. The first matching category is selected.
5555
|
5656
a| The result is a number equal to input and has the type
5757

58-
* `std::int64_t`, if `T` is a signed integer'; or
58+
* `std::int64_t`, if `T` is a signed integer; or
5959
* `std::uint64_t`, if `T` is an unsigned integer; or
6060
* `double` otherwise.
6161
|The result is created via <<ref_value_to_number>>.
6262
63-
|Type satisfying <<ref_is_null_like>>
63+
|<<ref_null_category>>
6464
|Intended for types like {std_monostate}.
6565
|The result is a null value.
6666
|The result is default-constructed.
6767

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

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

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

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

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

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

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

108-
|Type satisfying <<ref_is_described_enum>>
108+
|<<ref_described_enum_category>>
109109
|
110110
|If the input value is equal to one of the described enumerators, the result is
111111
a <<ref_string>>, containing its name. Otherwise it's equal to the input
112112
value converted to its underlying type.
113113
|The result is the described enumerator, corresponding to the input
114114
<<ref_string>>.
115115

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

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

doc/pages/definitions.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ Official repository: https://github.com/boostorg/json
1212
:ref_error_category: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_category[`error_category`]]
1313
:ref_error_code: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_code[`error_code`]]
1414
:ref_error_condition: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_error_condition[`error_condition`]]
15+
: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`]]
16+
:ref_path: pass:q[https://www.boost.org/doc/libs/latest/libs/filesystem/doc/reference.html#class-path[`boost::filesystem::path`]]
1517
:ref_result: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_resultt_e[`result`]]
1618
:ref_system_error: pass:q[https://boost.org/doc/libs/latest/libs/system/doc/html/system.html#ref_system_error[`system_error`]]
19+
:ref_variant: pass:q[https://www.boost.org/doc/libs/latest/libs/variant2/doc/html/variant2.html#ref_variant[`boost::variant2::variant`]]
1720

1821
:req_Allocator: pass:q[https://en.cppreference.com/w/cpp/named_req/Allocator[__Allocator__]]
1922
:req_CopyAssignable: pass:q[https://en.cppreference.com/w/cpp/named_req/CopyAssignable[__CopyAssignable__]]
@@ -33,12 +36,17 @@ Official repository: https://github.com/boostorg/json
3336
:std_initializer_list: pass:q[https://en.cppreference.com/w/cpp/utility/initializer_list[`std::initializer_list`]]
3437
:std_complex: pass:q[https://en.cppreference.com/w/cpp/numeric/complex[`std::complex`]]
3538
:std_hash: pass:q[https://en.cppreference.com/w/cpp/utility/hash[`std::hash`]]
39+
:std_map: pass:q[https://en.cppreference.com/w/cpp/container/map[`std::map`]]
3640
:std_memory_resource: pass:q[https://en.cppreference.com/w/cpp/memory/memory_resource[`std::pmr::memory_resource`]]
3741
:std_monostate: pass:q[https://en.cppreference.com/w/cpp/utility/variant/monostate[`std::monostate`]]
42+
:std_optional: pass:q[https://en.cppreference.com/w/cpp/utility/optional[`std::optional`]]
3843
:std_ostream: pass:q[https://en.cppreference.com/w/cpp/io/basic_ostream[`std::ostream`]]
44+
:std_pair: pass:q[https://en.cppreference.com/w/cpp/utility/pair[`std::pair`]]
45+
:std_path: pass:q[https://en.cppreference.com/w/cpp/filesystem/path[`std::filesystem::path`]]
3946
:std_polymorphic_allocator: pass:q[https://en.cppreference.com/w/cpp/memory/polymorphic_allocator[`std::pmr::polymorphic_allocator`]]
4047
:std_string: pass:q[https://en.cppreference.com/w/cpp/string/basic_string[`std::string`]]
4148
:std_unordered_map: pass:q[https://en.cppreference.com/w/cpp/container/unordered_map[`std::unordered_map`]]
4249
:std_uses_allocator: pass:q[https://en.cppreference.com/w/cpp/memory/uses_allocator[`std::uses_allocator`]]
50+
:std_variant: pass:q[https://en.cppreference.com/w/cpp/utility/variant[`std::variant`]]
4351
:std_vector: pass:q[https://en.cppreference.com/w/cpp/container/vector[`std::vector`]]
4452
:std_tuple: pass:q[https://en.cppreference.com/w/cpp/utility/tuple[`std::tuple`]]

doc/pages/reference.adoc

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ a| *Classes* +
3333
<<ref_value_ref>> +
3434
<<ref_value_stack>>
3535

36+
*Aliases* +
37+
<<ref_parser_for>> +
38+
<<ref_string_view>>
39+
3640
a| *Functions* +
3741
<<ref_get>> +
3842
<<ref_get_null_resource>> +
@@ -52,7 +56,7 @@ a| *Functions* +
5256
<<ref_pilfered>> +
5357
<<ref_is_pilfer_constructible>>
5458

55-
| *Operators* +
59+
a| *Operators* +
5660
<<ref_operator_eq_eq>> +
5761
<<ref_operator_not_eq>> +
5862
<<ref_operator_gt>> +
@@ -61,37 +65,53 @@ a| *Functions* +
6165
<<ref_operator_lt_eq>> +
6266
<<ref_operator_lt_lt>> +
6367

64-
*Aliases* +
65-
<<ref_parser_for>> +
66-
<<ref_string_view>>
67-
6868
*Constants* +
6969
<<ref_array_kind>> +
7070
<<ref_condition>> +
71+
<<ref_conversion_category>> +
7172
<<ref_error>> +
7273
<<ref_kind>> +
7374
<<ref_number_precision>> +
7475
<<ref_object_kind>> +
7576
<<ref_string_kind>>
7677

77-
| *Type Traits* +
78+
a| *Type Traits* +
79+
<<ref_described_class_category>> +
80+
<<ref_described_enum_category>> +
7881
<<ref_has_value_from>> +
7982
<<ref_has_value_to>> +
8083
<<ref_is_deallocate_trivial>> +
84+
<<ref_map_category>> +
85+
<<ref_null_category>> +
86+
<<ref_optional_category>> +
87+
<<ref_path_category>> +
88+
<<ref_result_for>> +
89+
<<ref_sequence_category>> +
90+
<<ref_string_category>> +
91+
<<ref_try_value_to_tag>> +
92+
<<ref_tuple_category>> +
93+
<<ref_use_category>> +
94+
<<ref_value_from_tag>> +
95+
<<ref_value_to_tag>> +
96+
<<ref_variant_category>> +
97+
<<ref_unknown_category>>
98+
99+
4+h|Deprecated
100+
101+
a|
81102
<<ref_is_described_class>> +
82103
<<ref_is_described_enum>> +
83-
<<ref_is_map_like>> +
104+
<<ref_is_map_like>>
105+
a|
84106
<<ref_is_null_like>> +
85-
<<ref_is_optional_like>> +
107+
<<ref_is_optional_like>>
108+
a|
86109
<<ref_is_path_like>> +
87110
<<ref_is_sequence_like>> +
88-
<<ref_is_string_like>> +
111+
<<ref_is_string_like>>
112+
a|
89113
<<ref_is_tuple_like>> +
90-
<<ref_is_variant_like>> +
91-
<<ref_result_for>> +
92-
<<ref_try_value_to_tag>> +
93-
<<ref_value_from_tag>> +
94-
<<ref_value_to_tag>>
114+
<<ref_is_variant_like>>
95115

96116
|===
97117

0 commit comments

Comments
 (0)