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 -
#include <boost/json/value.hpp>
 
15  

14  

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

18  

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

22  

24  
namespace boost {
23  
namespace boost {
25 -

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

26  

29  
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 >
30  
struct append_tuple_element {
32  
struct append_tuple_element {
31  
    array& arr;
33  
    array& arr;
32  
    Ctx const& ctx;
34  
    Ctx const& ctx;
33  
    T&& t;
35  
    T&& t;
34  

36  

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

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 +

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

64  

48  
template< class T, class Ctx >
65  
template< class T, class Ctx >
49  
void
66  
void
50  
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& )
51  
{
68  
{
52  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
69  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
53  
}
70  
}
54  

71  

55  
template< class T, class Ctx >
72  
template< class T, class Ctx >
56  
void
73  
void
57  
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)
58  
{
75  
{
59  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
76  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
60  
    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) );
61  
}
78  
}
62  

79  

63  
template< class T, class Ctx >
80  
template< class T, class Ctx >
64  
void
81  
void
65  
value_from_impl(
82  
value_from_impl(
66  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
83  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
67  
{
84  
{
68  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
85  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
69  
    tag_invoke(
86  
    tag_invoke(
70  
        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 );
71  
}
88  
}
72  

89  

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

92  

76  
template< class T, class Ctx >
93  
template< class T, class Ctx >
77  
void
94  
void
78  
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& )
79  
{
96  
{
80  
    jv = std::forward<T>(from);
97  
    jv = std::forward<T>(from);
81  
}
98  
}
82  

99  

83  
// null-like types
100  
// null-like types
84  
template< class T, class Ctx >
101  
template< class T, class Ctx >
85  
void
102  
void
86  
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& )
87  
{
104  
{
88  
    // do nothing
105  
    // do nothing
89  
    BOOST_ASSERT(jv.is_null());
106  
    BOOST_ASSERT(jv.is_null());
90  
    (void)jv;
107  
    (void)jv;
91  
}
108  
}
92  

109  

93  
// string-like types
110  
// string-like types
94  
template< class T, class Ctx >
111  
template< class T, class Ctx >
95  
void
112  
void
96  
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& )
97  
{
114  
{
98  
    auto sv = static_cast<string_view>(from);
115  
    auto sv = static_cast<string_view>(from);
99  
    jv.emplace_string().assign(sv);
116  
    jv.emplace_string().assign(sv);
100  
}
117  
}
101  

118  

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

134  

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

151  

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

164  

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

174  

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

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

179  

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

183  

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

197  

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

207  

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

213  

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

236  

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

248  

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

255  

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

263  

249  
template< class Ctx, class T >
264  
template< class Ctx, class T >
250  
void
265  
void
251  
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 )
252  
{
267  
{
253  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
268  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
254  
}
269  
}
255  

270  

256  
template< class Ctx, class T >
271  
template< class Ctx, class T >
257  
void
272  
void
258  
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& )
259  
{
274  
{
260  
    std::string s = from.generic_string();
275  
    std::string s = from.generic_string();
261  
    string_view sv = s;
276  
    string_view sv = s;
262  
    jv.emplace_string().assign(sv);
277  
    jv.emplace_string().assign(sv);
263 -

 
264 -
//----------------------------------------------------------
 
265 -
// Contextual conversions
 
266 -

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

279  

272  
} // detail
280  
} // detail
273  

281  

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

295  

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

298  

291  
#endif
299  
#endif