Coverage Report

Created: 2026-08-13 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/detail/value_from.hpp
Line
Count
Source
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
5
//
6
// Distributed under the Boost Software License, Version 1.0. (See accompanying
7
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8
//
9
// Official repository: https://github.com/boostorg/json
10
//
11
12
#ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
13
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
14
15
#include <boost/json/value.hpp>
16
#include <boost/json/conversion.hpp>
17
#include <boost/describe/enum_to_string.hpp>
18
#include <boost/mp11/algorithm.hpp>
19
20
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
21
# include <optional>
22
#endif
23
24
namespace boost {
25
namespace json {
26
27
namespace detail {
28
29
template< class Ctx, class T >
30
struct append_tuple_element {
31
    array& arr;
32
    Ctx const& ctx;
33
    T&& t;
34
35
    template<std::size_t I>
36
    void
37
    operator()(mp11::mp_size_t<I>) const
38
    {
39
        using std::get;
40
        arr.emplace_back(value_from(
41
            get<I>(std::forward<T>(t)), ctx, arr.storage() ));
42
    }
43
};
44
45
//----------------------------------------------------------
46
// User-provided conversion
47
48
template< class T, class Ctx >
49
void
50
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
51
{
52
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
53
}
54
55
template< class T, class Ctx >
56
void
57
value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
58
{
59
    using Sup = supported_context<Ctx, T, value_from_conversion>;
60
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
61
}
62
63
template< class T, class Ctx >
64
void
65
value_from_impl(
66
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
67
{
68
    using Sup = supported_context<Ctx, T, value_from_conversion>;
69
    tag_invoke(
70
        value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
71
}
72
73
//----------------------------------------------------------
74
// Native conversion
75
76
template< class T, class Ctx >
77
void
78
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
79
{
80
    jv = std::forward<T>(from);
81
}
82
83
// null-like types
84
template< class T, class Ctx >
85
void
86
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
87
{
88
    // do nothing
89
    BOOST_ASSERT(jv.is_null());
90
    (void)jv;
91
}
92
93
// string-like types
94
template< class T, class Ctx >
95
void
96
value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
97
{
98
    auto sv = static_cast<string_view>(from);
99
    jv.emplace_string().assign(sv);
100
}
101
102
// map-like types
103
template< class T, class Ctx >
104
void
105
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
106
{
107
    using std::get;
108
    object& obj = jv.emplace_object();
109
    obj.reserve(detail::try_size(from, size_implementation<T>()));
110
    for (auto&& elem : from)
111
        obj.emplace(
112
            get<0>(elem),
113
            value_from( get<1>(elem), ctx, obj.storage() ));
114
}
115
116
// ranges
117
template< class T, class Ctx >
118
void
119
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
120
{
121
    array& result = jv.emplace_array();
122
    result.reserve(detail::try_size(from, size_implementation<T>()));
123
    using ForwardedValue = forwarded_value<T&&>;
124
    for (auto&& elem : from)
125
        result.emplace_back(
126
            value_from(
127
                // not a static_cast in order to appease clang < 4.0
128
                ForwardedValue(elem),
129
                ctx,
130
                result.storage() ));
131
}
132
133
// tuple-like types
134
template< class T, class Ctx >
135
void
136
value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
137
{
138
    constexpr std::size_t n =
139
        std::tuple_size<remove_cvref<T>>::value;
140
    array& arr = jv.emplace_array();
141
    arr.reserve(n);
142
    mp11::mp_for_each<mp11::mp_iota_c<n>>(
143
        append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
144
}
145
146
// no suitable conversion implementation
147
template< class T, class Ctx >
148
void
149
value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
150
{
151
    static_assert(
152
        !std::is_same<T, T>::value,
153
        "No suitable tag_invoke overload found for the type");
154
}
155
156
template< class Ctx, class T >
157
struct from_described_member
158
{
159
    static_assert(
160
        uniquely_named_members< remove_cvref<T> >::value,
161
        "The type has several described members with the same name.");
162
163
    using Ds = described_members< remove_cvref<T> >;
164
165
    object& obj;
166
    Ctx const& ctx;
167
    T&& from;
168
169
    template< class I >
170
    void
171
    operator()(I) const
172
    {
173
        using D = mp11::mp_at<Ds, I>;
174
        obj.emplace(
175
            D::name,
176
            value_from(
177
                static_cast<T&&>(from).* D::pointer,
178
                ctx,
179
                obj.storage()));
180
    }
181
};
182
183
// described classes
184
template< class T, class Ctx >
185
void
186
value_from_impl(
187
    described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
188
{
189
    object& obj = jv.emplace_object();
190
    from_described_member<Ctx, T> member_converter{
191
        obj, ctx, static_cast<T&&>(from)};
192
193
    using Ds = typename decltype(member_converter)::Ds;
194
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
195
    obj.reserve(N);
196
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
197
}
198
199
// described enums
200
template< class T, class Ctx >
201
void
202
value_from_impl(
203
    described_enum_conversion_tag, value& jv, T from, Ctx const& )
204
{
205
    (void)jv;
206
    (void)from;
207
#ifdef BOOST_DESCRIBE_CXX14
208
    char const* const name = describe::enum_to_string(from, nullptr);
209
    if( name )
210
    {
211
        string& str = jv.emplace_string();
212
        str.assign(name);
213
    }
214
    else
215
    {
216
        using Integer = typename std::underlying_type< remove_cvref<T> >::type;
217
        jv = static_cast<Integer>(from);
218
    }
219
#endif
220
}
221
222
// optionals
223
template< class T, class Ctx >
224
void
225
value_from_impl(
226
    optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
227
{
228
    if( from )
229
        value_from( *from, ctx, jv );
230
    else
231
        jv = nullptr;
232
}
233
234
// variants
235
template< class Ctx >
236
struct value_from_visitor
237
{
238
    value& jv;
239
    Ctx const& ctx;
240
241
    template<class T>
242
    void
243
    operator()(T&& t)
244
    {
245
        value_from( static_cast<T&&>(t), ctx, jv );
246
    }
247
};
248
249
template< class Ctx, class T >
250
void
251
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
252
{
253
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
254
}
255
256
template< class Ctx, class T >
257
void
258
value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
259
{
260
    std::string s = from.generic_string();
261
    string_view sv = s;
262
    jv.emplace_string().assign(sv);
263
}
264
265
//----------------------------------------------------------
266
// Contextual conversions
267
268
template< class Ctx, class T >
269
using value_from_category = conversion_category<
270
    Ctx, T, value_from_conversion >;
271
272
} // detail
273
274
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
275
inline
276
void
277
tag_invoke(
278
    value_from_tag,
279
    value& jv,
280
    std::nullopt_t)
281
0
{
282
0
    // do nothing
283
0
    BOOST_ASSERT(jv.is_null());
284
0
    (void)jv;
285
0
}
286
#endif
287
288
} // namespace json
289
} // namespace boost
290
291
#endif