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

19  

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

23  

23  
namespace boost {
24  
namespace boost {
24  
namespace json {
25  
namespace json {
25  

26  

26  
namespace detail {
27  
namespace detail {
27  

28  

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

34  

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

44  

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

47  

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

54  

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

62  

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

72  

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

75  

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

82  

82  
// null-like types
83  
// null-like types
83  
template< class T, class Ctx >
84  
template< class T, class Ctx >
84  
void
85  
void
85  
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& )
86  
{
87  
{
87  
    // do nothing
88  
    // do nothing
88  
    BOOST_ASSERT(jv.is_null());
89  
    BOOST_ASSERT(jv.is_null());
89  
    (void)jv;
90  
    (void)jv;
90  
}
91  
}
91  

92  

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

101  

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

115  

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

132  

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

145  

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

155  

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

162  

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

164  

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

168  

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

182  

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

192  

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

198  

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

221  

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

233  

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

240  

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

248  

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

255  

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

264  

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

267  

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

271  

271  
} // detail
272  
} // detail
272  

273  

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

287  

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

290  

290  
#endif
291  
#endif