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/value.hpp>
15  
#include <boost/json/value.hpp>
16  
#include <boost/json/conversion.hpp>
16  
#include <boost/json/conversion.hpp>
17  
#include <boost/describe/enum_to_string.hpp>
17  
#include <boost/describe/enum_to_string.hpp>
18  
#include <boost/mp11/algorithm.hpp>
18  
#include <boost/mp11/algorithm.hpp>
19  

19  

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

23  

24  
namespace boost {
24  
namespace boost {
25  
namespace json {
25  
namespace json {
26  

26  

27  
namespace detail {
27  
namespace detail {
28  

28  

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

34  

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

44  

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

47  

48  
template< class T, class Ctx >
48  
template< class T, class Ctx >
49  
void
49  
void
50  
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
50  
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
51  
{
51  
{
52  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
52  
    tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
53  
}
53  
}
54  

54  

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

62  

63  
template< class T, class Ctx >
63  
template< class T, class Ctx >
64  
void
64  
void
65  
value_from_impl(
65  
value_from_impl(
66  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
66  
    full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
67  
{
67  
{
68  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
68  
    using Sup = supported_context<Ctx, T, value_from_conversion>;
69  
    tag_invoke(
69  
    tag_invoke(
70  
        value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
70  
        value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
71  
}
71  
}
72  

72  

73  
//----------------------------------------------------------
73  
//----------------------------------------------------------
74  
// Native conversion
74  
// Native conversion
75  

75  

76  
template< class T, class Ctx >
76  
template< class T, class Ctx >
77  
void
77  
void
78  
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
78  
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
79  
{
79  
{
80  
    jv = std::forward<T>(from);
80  
    jv = std::forward<T>(from);
81  
}
81  
}
82  

82  

83  
// null-like types
83  
// null-like types
84  
template< class T, class Ctx >
84  
template< class T, class Ctx >
85  
void
85  
void
86  
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
86  
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
87  
{
87  
{
88  
    // do nothing
88  
    // do nothing
89  
    BOOST_ASSERT(jv.is_null());
89  
    BOOST_ASSERT(jv.is_null());
90  
    (void)jv;
90  
    (void)jv;
91  
}
91  
}
92  

92  

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

101  

102  
// map-like types
102  
// map-like types
103  
template< class T, class Ctx >
103  
template< class T, class Ctx >
104  
void
104  
void
105  
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
105  
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
106  
{
106  
{
107  
    using std::get;
107  
    using std::get;
108  
    object& obj = jv.emplace_object();
108  
    object& obj = jv.emplace_object();
109  
    obj.reserve(detail::try_size(from, size_implementation<T>()));
109  
    obj.reserve(detail::try_size(from, size_implementation<T>()));
110  
    for (auto&& elem : from)
110  
    for (auto&& elem : from)
111  
        obj.emplace(
111  
        obj.emplace(
112  
            get<0>(elem),
112  
            get<0>(elem),
113  
            value_from( get<1>(elem), ctx, obj.storage() ));
113  
            value_from( get<1>(elem), ctx, obj.storage() ));
114  
}
114  
}
115  

115  

116  
// ranges
116  
// ranges
117  
template< class T, class Ctx >
117  
template< class T, class Ctx >
118  
void
118  
void
119  
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
119  
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
120  
{
120  
{
121  
    array& result = jv.emplace_array();
121  
    array& result = jv.emplace_array();
122  
    result.reserve(detail::try_size(from, size_implementation<T>()));
122  
    result.reserve(detail::try_size(from, size_implementation<T>()));
123  
    using ForwardedValue = forwarded_value<T&&>;
123  
    using ForwardedValue = forwarded_value<T&&>;
124  
    for (auto&& elem : from)
124  
    for (auto&& elem : from)
125  
        result.emplace_back(
125  
        result.emplace_back(
126  
            value_from(
126  
            value_from(
127  
                // not a static_cast in order to appease clang < 4.0
127  
                // not a static_cast in order to appease clang < 4.0
128  
                ForwardedValue(elem),
128  
                ForwardedValue(elem),
129  
                ctx,
129  
                ctx,
130  
                result.storage() ));
130  
                result.storage() ));
131  
}
131  
}
132  

132  

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

145  

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

155  

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

162  

163  
    using Ds = described_members< remove_cvref<T> >;
163  
    using Ds = described_members< remove_cvref<T> >;
164  

164  

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

168  

169  
    template< class I >
169  
    template< class I >
170  
    void
170  
    void
171  
    operator()(I) const
171  
    operator()(I) const
172  
    {
172  
    {
173  
        using D = mp11::mp_at<Ds, I>;
173  
        using D = mp11::mp_at<Ds, I>;
174  
        obj.emplace(
174  
        obj.emplace(
175  
            D::name,
175  
            D::name,
176  
            value_from(
176  
            value_from(
177  
                static_cast<T&&>(from).* D::pointer,
177  
                static_cast<T&&>(from).* D::pointer,
178  
                ctx,
178  
                ctx,
179  
                obj.storage()));
179  
                obj.storage()));
180  
    }
180  
    }
181  
};
181  
};
182  

182  

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

192  

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

198  

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

221  

222  
// optionals
222  
// optionals
223  
template< class T, class Ctx >
223  
template< class T, class Ctx >
224  
void
224  
void
225  
value_from_impl(
225  
value_from_impl(
226  
    optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
226  
    optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
227  
{
227  
{
228  
    if( from )
228  
    if( from )
229  
        value_from( *from, ctx, jv );
229  
        value_from( *from, ctx, jv );
230  
    else
230  
    else
231  
        jv = nullptr;
231  
        jv = nullptr;
232  
}
232  
}
233  

233  

234  
// variants
234  
// variants
235  
template< class Ctx >
235  
template< class Ctx >
236  
struct value_from_visitor
236  
struct value_from_visitor
237  
{
237  
{
238  
    value& jv;
238  
    value& jv;
239  
    Ctx const& ctx;
239  
    Ctx const& ctx;
240  

240  

241  
    template<class T>
241  
    template<class T>
242  
    void
242  
    void
243  
    operator()(T&& t)
243  
    operator()(T&& t)
244  
    {
244  
    {
245  
        value_from( static_cast<T&&>(t), ctx, jv );
245  
        value_from( static_cast<T&&>(t), ctx, jv );
246  
    }
246  
    }
247  
};
247  
};
248  

248  

249  
template< class Ctx, class T >
249  
template< class Ctx, class T >
250  
void
250  
void
251  
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
251  
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
252  
{
252  
{
253  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
253  
    visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
254  
}
254  
}
255  

255  

256  
template< class Ctx, class T >
256  
template< class Ctx, class T >
257  
void
257  
void
258  
value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
258  
value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
259  
{
259  
{
260  
    std::string s = from.generic_string();
260  
    std::string s = from.generic_string();
261  
    string_view sv = s;
261  
    string_view sv = s;
262  
    jv.emplace_string().assign(sv);
262  
    jv.emplace_string().assign(sv);
263  
}
263  
}
264  

264  

265  
//----------------------------------------------------------
265  
//----------------------------------------------------------
266  
// Contextual conversions
266  
// Contextual conversions
267  

267  

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

271  

272  
} // detail
272  
} // detail
273  

273  

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

287  

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

290  

291  
#endif
291  
#endif