Skip to content

Commit

Permalink
value_to supports missing elements for std::optional
Browse files Browse the repository at this point in the history
  • Loading branch information
grisumbras committed Nov 16, 2022
1 parent e979855 commit 8f7e7c8
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 10 deletions.
50 changes: 41 additions & 9 deletions include/boost/json/detail/value_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,18 @@ value_to_impl(
*arr, boost::mp11::make_index_sequence<N>());
}

template< class T>
struct is_optional
: std::false_type
{ };

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
template< class T>
struct is_optional< std::optional<T> >
: std::true_type
{ };
#endif // BOOST_NO_CXX17_HDR_OPTIONAL

template< class T >
struct to_described_member
{
Expand All @@ -477,28 +489,44 @@ struct to_described_member

result<T>& res;
object const& obj;
std::size_t count = 0u;

template< class I >
void
operator()(I) const
operator()(I)
{
if( !res )
return;

using D = mp11::mp_at<Ds, I>;
using M = described_member_t<D>;

auto const found = obj.find(D::name);
if( found == obj.end() )
{
error_code ec;
BOOST_JSON_FAIL(ec, error::unknown_name);
res = {boost::system::in_place_error, ec};
BOOST_IF_CONSTEXPR( !is_optional<M>::value )
{
error_code ec;
BOOST_JSON_FAIL(ec, error::unknown_name);
res = {boost::system::in_place_error, ec};
}
return;
}

using M = described_member_t<D>;
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused"
# pragma GCC diagnostic ignored "-Wunused-variable"
#endif
auto member_res = try_value_to<M>(found->value());
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
# pragma GCC diagnostic pop
#endif
if( member_res )
{
(*res).* D::pointer = std::move(*member_res);
++count;
}
else
res = {boost::system::in_place_error, member_res.error()};
}
Expand All @@ -523,19 +551,23 @@ value_to_impl(
return res;
}

to_described_member<T> member_converter{res, *obj};
using Ds = typename decltype(member_converter)::Ds;
to_described_member<T> member_converter{res, *obj, 0u};

using Ds = typename decltype(member_converter)::Ds;
constexpr std::size_t N = mp11::mp_size<Ds>::value;
if( obj->size() != N )
mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);

if( !res )
return res;

if( member_converter.count != obj->size() )
{
error_code ec;
BOOST_JSON_FAIL(ec, error::size_mismatch);
res = {boost::system::in_place_error, ec};
return res;
}

mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
return res;
}

Expand Down
35 changes: 34 additions & 1 deletion test/value_to.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ BOOST_DESCRIBE_STRUCT(T7, (T6), (s))

BOOST_DEFINE_ENUM_CLASS(E1, a, b, c)

//----------------------------------------------------------

struct T8
{
int n;
double d;
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
std::optional<std::string> opt_s;
#else
std::string opt_s;
#endif // BOOST_NO_CXX17_HDR_OPTIONAL
};
BOOST_DESCRIBE_STRUCT(T8, (), (n, d, opt_s))

} // namespace value_to_test_ns

namespace std
Expand Down Expand Up @@ -317,6 +331,10 @@ class value_to_test
BOOST_TEST( res );
BOOST_TEST( res->n == -78 );
BOOST_TEST( res->d == 0.125 );

jv.as_object()["x"] = 0;
BOOST_TEST_THROWS_WITH_LOCATION(
value_to<::value_to_test_ns::T6>( jv ));
}
{
value jv = {{"n", 1}, {"d", 2}, {"s", "xyz"}};
Expand Down Expand Up @@ -348,7 +366,22 @@ class value_to_test
value_to<::value_to_test_ns::E1>( value(1) ));
BOOST_TEST_THROWS_WITH_LOCATION(
value_to<::value_to_test_ns::E1>( value("x") ));
#endif

{
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
value jv = {{"n", -78}, {"d", 0.125}};
auto res = try_value_to<::value_to_test_ns::T8>(jv);
BOOST_TEST( res );
BOOST_TEST( res->n == -78 );
BOOST_TEST( res->d == 0.125 );
BOOST_TEST( std::nullopt == res->opt_s );

jv.as_object()["x"] = 0;
BOOST_TEST_THROWS_WITH_LOCATION(
value_to<::value_to_test_ns::T8>( jv ));
#endif // BOOST_NO_CXX17_HDR_OPTIONAL
}
#endif // BOOST_DESCRIBE_CXX14
}

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
Expand Down

0 comments on commit 8f7e7c8

Please sign in to comment.