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  
namespace json {
24  
namespace json {
25  

25  

26  
namespace detail {
26  
namespace detail {
27  

27  

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

33  

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

43  

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

46  

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

53  

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

61  

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

71  

72  
//----------------------------------------------------------
72  
//----------------------------------------------------------
73  
// Native conversion
73  
// Native conversion
74  

74  

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

81  

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

91  

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

100  

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

114  

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

131  

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

144  

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

154  

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

161  

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

163  

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

167  

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

181  

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

191  

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

197  

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

220  

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

232  

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

239  

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

247  

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

254  

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

263  

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

266  

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

270  

271  
} // detail
271  
} // detail
272  

272  

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

286  

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

289  

290  
#endif
290  
#endif