1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4  
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
4  
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
5  
//
5  
//
6  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
7  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8  
//
8  
//
9  
// Official repository: https://github.com/boostorg/json
9  
// Official repository: https://github.com/boostorg/json
10  
//
10  
//
11  

11  

12  
#ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
12  
#ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
13  
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
13  
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
14  

14  

15  
#include <boost/json/conversion.hpp>
15  
#include <boost/json/conversion.hpp>
16  
#include <boost/describe/enum_to_string.hpp>
16  
#include <boost/describe/enum_to_string.hpp>
17  
#include <boost/mp11/algorithm.hpp>
17  
#include <boost/mp11/algorithm.hpp>
18  

18  

19  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
19  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
20  
# include <optional>
20  
# include <optional>
21  
#endif
21  
#endif
22  

22  

23  
namespace boost {
23  
namespace boost {
24 -

 
25  
namespace json {
24  
namespace json {
26  
namespace detail {
25  
namespace detail {
27  

26  

28  
template< class Ctx, class T >
27  
template< class Ctx, class T >
 
28 +
using value_from_attrs = conversion_attrs<
 
29 +
    Ctx, remove_cvref<T>, value_from_conversion>;
 
30 +

 
31 +
template< class Ctx, class T >
29  
struct append_tuple_element {
32  
struct append_tuple_element {
30  
    array& arr;
33  
    array& arr;
31  
    Ctx const& ctx;
34  
    Ctx const& ctx;
32  
    T&& t;
35  
    T&& t;
33  

36  

34  
    template<std::size_t I>
37  
    template<std::size_t I>
35  
    void
38  
    void
36  
    operator()(mp11::mp_size_t<I>) const
39  
    operator()(mp11::mp_size_t<I>) const
37  
    {
40  
    {
38  
        using std::get;
41  
        using std::get;
39  
        arr.emplace_back(value_from(
42  
        arr.emplace_back(value_from(
40  
            get<I>(std::forward<T>(t)), ctx, arr.storage() ));
43  
            get<I>(std::forward<T>(t)), ctx, arr.storage() ));
41  
    }
44  
    }
42  
};
45  
};
43  

46  

 
47 +
template< class T, class Ctx >
 
48 +
using to_representation_result = mp11::mp_if<
 
49 +
    std::is_same<
 
50 +
        remove_cvref<T>, typename value_from_attrs<Ctx, T>::representation >,
 
51 +
    T&&,
 
52 +
    typename value_from_attrs<Ctx, T>::representation>;
 
53 +

 
54 +
template< class Ctx, class T >
 
55 +
to_representation_result< T, Ctx >
 
56 +
to_representation( T&& t )
 
57 +
{
 
58 +
    using R = to_representation_result< T, Ctx >;
 
59 +
    return static_cast<R>( static_cast<T&&>(t) );
 
60 +
}
 
61 +

44  
//----------------------------------------------------------
62  
//----------------------------------------------------------
45  
// User-provided conversion
63  
// User-provided conversion
46  

64  

47  
template< class T, class Ctx >
65  
template< class T, class Ctx >
48  
void
66  
void
49  
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
67  
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
50  
{
68  
{
51  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
69  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
52  
}
70  
}
53  

71  

54  
template< class T, class Ctx >
72  
template< class T, class Ctx >
55  
void
73  
void
56  
value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
74  
value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
57  
{
75  
{
58  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
76  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
59  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
77  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
60  
}
78  
}
61  

79  

62  
template< class T, class Ctx >
80  
template< class T, class Ctx >
63  
void
81  
void
64  
value_from_impl(
82  
value_from_impl(
65  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
83  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
66  
{
84  
{
67  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
85  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
68  
    tag_invoke(
86  
    tag_invoke(
69  
        value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
87  
        value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
70  
}
88  
}
71  

89  

72  
//----------------------------------------------------------
90  
//----------------------------------------------------------
73  
// Native conversion
91  
// Native conversion
74  

92  

75  
template< class T, class Ctx >
93  
template< class T, class Ctx >
76  
void
94  
void
77  
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
95  
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
78  
{
96  
{
79  
    jv = std::forward<T>(from);
97  
    jv = std::forward<T>(from);
80  
}
98  
}
81  

99  

82  
// null-like types
100  
// null-like types
83  
template< class T, class Ctx >
101  
template< class T, class Ctx >
84  
void
102  
void
85  
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
103  
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
86  
{
104  
{
87  
    // do nothing
105  
    // do nothing
88  
    BOOST_ASSERT(jv.is_null());
106  
    BOOST_ASSERT(jv.is_null());
89  
    (void)jv;
107  
    (void)jv;
90  
}
108  
}
91  

109  

92  
// string-like types
110  
// string-like types
93  
template< class T, class Ctx >
111  
template< class T, class Ctx >
94  
void
112  
void
95  
value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
113  
value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
96  
{
114  
{
97  
    auto sv = static_cast<string_view>(from);
115  
    auto sv = static_cast<string_view>(from);
98  
    jv.emplace_string().assign(sv);
116  
    jv.emplace_string().assign(sv);
99  
}
117  
}
100  

118  

101  
// map-like types
119  
// map-like types
102  
template< class T, class Ctx >
120  
template< class T, class Ctx >
103  
void
121  
void
104  
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
122  
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
105  
{
123  
{
106  
    using std::get;
124  
    using std::get;
107  
    object& obj = jv.emplace_object();
125  
    object& obj = jv.emplace_object();
108  
    obj.reserve(detail::try_size(from, size_implementation<T>()));
126  
    obj.reserve(detail::try_size(from, size_implementation<T>()));
109  
    for (auto&& elem : from)
127  
    for (auto&& elem : from)
 
128 +
    {
110  
        obj.emplace(
129  
        obj.emplace(
111 -
            get<0>(elem),
130 +
            to_representation<Ctx>( get<0>(elem) ),
112  
            value_from( get<1>(elem), ctx, obj.storage() ));
131  
            value_from( get<1>(elem), ctx, obj.storage() ));
 
132 +
    }
113  
}
133  
}
114  

134  

115  
// ranges
135  
// ranges
116  
template< class T, class Ctx >
136  
template< class T, class Ctx >
117  
void
137  
void
118  
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
138  
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
119  
{
139  
{
120  
    array& result = jv.emplace_array();
140  
    array& result = jv.emplace_array();
121  
    result.reserve(detail::try_size(from, size_implementation<T>()));
141  
    result.reserve(detail::try_size(from, size_implementation<T>()));
122  
    using ForwardedValue = forwarded_value<T&&>;
142  
    using ForwardedValue = forwarded_value<T&&>;
123  
    for (auto&& elem : from)
143  
    for (auto&& elem : from)
124  
        result.emplace_back(
144  
        result.emplace_back(
125  
            value_from(
145  
            value_from(
126  
                // not a static_cast in order to appease clang < 4.0
146  
                // not a static_cast in order to appease clang < 4.0
127  
                ForwardedValue(elem),
147  
                ForwardedValue(elem),
128  
                ctx,
148  
                ctx,
129  
                result.storage() ));
149  
                result.storage() ));
130  
}
150  
}
131  

151  

132  
// tuple-like types
152  
// tuple-like types
133  
template< class T, class Ctx >
153  
template< class T, class Ctx >
134  
void
154  
void
135  
value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
155  
value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
136  
{
156  
{
137  
    constexpr std::size_t n =
157  
    constexpr std::size_t n =
138  
        std::tuple_size<remove_cvref<T>>::value;
158  
        std::tuple_size<remove_cvref<T>>::value;
139  
    array& arr = jv.emplace_array();
159  
    array& arr = jv.emplace_array();
140  
    arr.reserve(n);
160  
    arr.reserve(n);
141  
    mp11::mp_for_each<mp11::mp_iota_c<n>>(
161  
    mp11::mp_for_each<mp11::mp_iota_c<n>>(
142  
        append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
162  
        append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
143  
}
163  
}
144  

164  

145  
// no suitable conversion implementation
165  
// no suitable conversion implementation
146  
template< class T, class Ctx >
166  
template< class T, class Ctx >
147  
void
167  
void
148  
value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
168  
value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
149  
{
169  
{
150  
    static_assert(
170  
    static_assert(
151  
        !std::is_same<T, T>::value,
171  
        !std::is_same<T, T>::value,
152  
        "No suitable tag_invoke overload found for the type");
172  
        "No suitable tag_invoke overload found for the type");
153  
}
173  
}
154  

174  

155  
template< class Ctx, class T >
175  
template< class Ctx, class T >
156  
struct from_described_member
176  
struct from_described_member
157 -
    static_assert(
 
158 -
        uniquely_named_members< remove_cvref<T> >::value,
 
159 -
        "The type has several described members with the same name.");
 
160 -

 
161  
{
177  
{
162  
    using Ds = described_members< remove_cvref<T> >;
178  
    using Ds = described_members< remove_cvref<T> >;
163  

179  

164  
    object& obj;
180  
    object& obj;
165  
    Ctx const& ctx;
181  
    Ctx const& ctx;
166  
    T&& from;
182  
    T&& from;
167  

183  

168  
    template< class I >
184  
    template< class I >
169  
    void
185  
    void
170  
    operator()(I) const
186  
    operator()(I) const
171  
    {
187  
    {
172  
        using D = mp11::mp_at<Ds, I>;
188  
        using D = mp11::mp_at<Ds, I>;
173  
        obj.emplace(
189  
        obj.emplace(
174  
            D::name,
190  
            D::name,
175  
            value_from(
191  
            value_from(
176  
                static_cast<T&&>(from).* D::pointer,
192  
                static_cast<T&&>(from).* D::pointer,
177  
                ctx,
193  
                ctx,
178  
                obj.storage()));
194  
                obj.storage()));
179  
    }
195  
    }
180  
};
196  
};
181  

197  

182  
// described classes
198  
// described classes
183  
template< class T, class Ctx >
199  
template< class T, class Ctx >
184  
void
200  
void
185  
value_from_impl(
201  
value_from_impl(
186  
    described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
202  
    described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
187  
{
203  
{
188  
    object& obj = jv.emplace_object();
204  
    object& obj = jv.emplace_object();
189  
    from_described_member<Ctx, T> member_converter{
205  
    from_described_member<Ctx, T> member_converter{
190  
        obj, ctx, static_cast<T&&>(from)};
206  
        obj, ctx, static_cast<T&&>(from)};
191  

207  

192  
    using Ds = typename decltype(member_converter)::Ds;
208  
    using Ds = typename decltype(member_converter)::Ds;
193  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
209  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
194  
    obj.reserve(N);
210  
    obj.reserve(N);
195  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
211  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
196  
}
212  
}
197  

213  

198  
// described enums
214  
// described enums
199  
template< class T, class Ctx >
215  
template< class T, class Ctx >
200  
void
216  
void
201  
value_from_impl(
217  
value_from_impl(
202  
    described_enum_conversion_tag, value& jv, T from, Ctx const& )
218  
    described_enum_conversion_tag, value& jv, T from, Ctx const& )
203  
{
219  
{
204  
    (void)jv;
220  
    (void)jv;
205  
    (void)from;
221  
    (void)from;
206  
#ifdef BOOST_DESCRIBE_CXX14
222  
#ifdef BOOST_DESCRIBE_CXX14
207  
    char const* const name = describe::enum_to_string(from, nullptr);
223  
    char const* const name = describe::enum_to_string(from, nullptr);
208  
    if( name )
224  
    if( name )
209  
    {
225  
    {
210  
        string& str = jv.emplace_string();
226  
        string& str = jv.emplace_string();
211  
        str.assign(name);
227  
        str.assign(name);
212  
    }
228  
    }
213  
    else
229  
    else
214  
    {
230  
    {
215  
        using Integer = typename std::underlying_type< remove_cvref<T> >::type;
231  
        using Integer = typename std::underlying_type< remove_cvref<T> >::type;
216  
        jv = static_cast<Integer>(from);
232  
        jv = static_cast<Integer>(from);
217  
    }
233  
    }
218  
#endif
234  
#endif
219  
}
235  
}
220  

236  

221  
// optionals
237  
// optionals
222  
template< class T, class Ctx >
238  
template< class T, class Ctx >
223  
void
239  
void
224  
value_from_impl(
240  
value_from_impl(
225  
    optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
241  
    optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
226  
{
242  
{
227  
    if( from )
243  
    if( from )
228  
        value_from( *from, ctx, jv );
244  
        value_from( *from, ctx, jv );
229  
    else
245  
    else
230  
        jv = nullptr;
246  
        jv = nullptr;
231  
}
247  
}
232  

248  

233  
// variants
249  
// variants
234  
template< class Ctx >
250  
template< class Ctx >
235  
struct value_from_visitor
251  
struct value_from_visitor
236  
{
252  
{
237  
    value& jv;
253  
    value& jv;
238  
    Ctx const& ctx;
254  
    Ctx const& ctx;
239  

255  

240  
    template<class T>
256  
    template<class T>
241  
    void
257  
    void
242  
    operator()(T&& t)
258  
    operator()(T&& t)
243  
    {
259  
    {
244  
        value_from( static_cast<T&&>(t), ctx, jv );
260  
        value_from( static_cast<T&&>(t), ctx, jv );
245  
    }
261  
    }
246  
};
262  
};
247  

263  

248  
template< class Ctx, class T >
264  
template< class Ctx, class T >
249  
void
265  
void
250  
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
266  
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
251  
{
267  
{
252  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
268  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
253  
}
269  
}
254  

270  

255  
template< class Ctx, class T >
271  
template< class Ctx, class T >
256  
void
272  
void
257  
value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
273  
value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
258  
{
274  
{
259  
    std::string s = from.generic_string();
275  
    std::string s = from.generic_string();
260  
    string_view sv = s;
276  
    string_view sv = s;
261  
    jv.emplace_string().assign(sv);
277  
    jv.emplace_string().assign(sv);
262 -

 
263 -
//----------------------------------------------------------
 
264 -
// Contextual conversions
 
265 -

 
266 -
template< class Ctx, class T >
 
267 -
using value_from_category = conversion_category<
 
268 -
    Ctx, T, value_from_conversion >;
 
269  
}
278  
}
270  

279  

271  
} // detail
280  
} // detail
272  

281  

273  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
282  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
274  
inline
283  
inline
275  
void
284  
void
276  
tag_invoke(
285  
tag_invoke(
277  
    value_from_tag,
286  
    value_from_tag,
278  
    value& jv,
287  
    value& jv,
279  
    std::nullopt_t)
288  
    std::nullopt_t)
280  
{
289  
{
281  
    // do nothing
290  
    // do nothing
282  
    BOOST_ASSERT(jv.is_null());
291  
    BOOST_ASSERT(jv.is_null());
283  
    (void)jv;
292  
    (void)jv;
284  
}
293  
}
285  
#endif
294  
#endif
286  

295  

287  
} // namespace json
296  
} // namespace json
288  
} // namespace boost
297  
} // namespace boost
289  

298  

290  
#endif
299  
#endif