Unverified Commit 0e694b40 authored by Théo DELRIEU's avatar Théo DELRIEU Committed by GitHub

fix std::filesystem::path regression (#3073)

* meta: rework is_compatible/is_constructible_string_type

These type traits performed an incorrect and insufficient check.

Converting to a std::filesystem::path used to work by accident thanks to
these brittle constraints, but the clean-up performed in #3020 broke them.

* support std::filesystem::path

Fixes #3070
parent 4b1cb9ee
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#ifdef JSON_HAS_CPP_17
#include <filesystem>
#endif
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
...@@ -169,7 +173,7 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l) ...@@ -169,7 +173,7 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l)
} }
template<typename BasicJsonType, typename T, std::size_t N> template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void()) -> decltype(j.template get<T>(), void())
{ {
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
...@@ -444,6 +448,18 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE ...@@ -444,6 +448,18 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE
} }
} }
#ifdef JSON_HAS_CPP_17
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, std::filesystem::path& p)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j));
}
p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
#endif
struct from_json_fn struct from_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
......
...@@ -9,11 +9,16 @@ ...@@ -9,11 +9,16 @@
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#ifdef JSON_HAS_CPP_17
#include <filesystem>
#endif
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
...@@ -386,6 +391,14 @@ void to_json(BasicJsonType& j, const T& t) ...@@ -386,6 +391,14 @@ void to_json(BasicJsonType& j, const T& t)
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
} }
#ifdef JSON_HAS_CPP_17
template<typename BasicJsonType>
void to_json(BasicJsonType& j, const std::filesystem::path& p)
{
j = p.string();
}
#endif
struct to_json_fn struct to_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
......
...@@ -309,44 +309,21 @@ struct is_constructible_object_type ...@@ -309,44 +309,21 @@ struct is_constructible_object_type
: is_constructible_object_type_impl<BasicJsonType, : is_constructible_object_type_impl<BasicJsonType,
ConstructibleObjectType> {}; ConstructibleObjectType> {};
template<typename BasicJsonType, typename CompatibleStringType,
typename = void>
struct is_compatible_string_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleStringType> template<typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type_impl < struct is_compatible_string_type
BasicJsonType, CompatibleStringType,
enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
range_value_t,
CompatibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
}; };
template<typename BasicJsonType, typename ConstructibleStringType> template<typename BasicJsonType, typename ConstructibleStringType>
struct is_compatible_string_type struct is_constructible_string_type
: is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
template<typename BasicJsonType, typename ConstructibleStringType,
typename = void>
struct is_constructible_string_type_impl : std::false_type {};
template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type_impl <
BasicJsonType, ConstructibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
value_type_t, ConstructibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
is_constructible<ConstructibleStringType, is_constructible<ConstructibleStringType,
typename BasicJsonType::string_t>::value; typename BasicJsonType::string_t>::value;
}; };
template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type
: is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
template<typename BasicJsonType, typename CompatibleArrayType, typename = void> template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {}; struct is_compatible_array_type_impl : std::false_type {};
...@@ -355,7 +332,10 @@ struct is_compatible_array_type_impl < ...@@ -355,7 +332,10 @@ struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType, BasicJsonType, CompatibleArrayType,
enable_if_t < enable_if_t <
is_detected<iterator_t, CompatibleArrayType>::value&& is_detected<iterator_t, CompatibleArrayType>::value&&
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value >> is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
// special case for types like std::filesystem::path whose iterator's value_type are themselves
// c.f. https://github.com/nlohmann/json/pull/3073
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
{ {
static constexpr bool value = static constexpr bool value =
is_constructible<BasicJsonType, is_constructible<BasicJsonType,
...@@ -388,8 +368,11 @@ struct is_constructible_array_type_impl < ...@@ -388,8 +368,11 @@ struct is_constructible_array_type_impl <
is_detected<iterator_t, ConstructibleArrayType>::value&& is_detected<iterator_t, ConstructibleArrayType>::value&&
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
is_detected<range_value_t, ConstructibleArrayType>::value&& is_detected<range_value_t, ConstructibleArrayType>::value&&
is_complete_type < // special case for types like std::filesystem::path whose iterator's value_type are themselves
detected_t<range_value_t, ConstructibleArrayType >>::value >> // c.f. https://github.com/nlohmann/json/pull/3073
!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
is_complete_type <
detected_t<range_value_t, ConstructibleArrayType >>::value >>
{ {
using value_type = range_value_t<ConstructibleArrayType>; using value_type = range_value_t<ConstructibleArrayType>;
......
...@@ -3783,44 +3783,21 @@ struct is_constructible_object_type ...@@ -3783,44 +3783,21 @@ struct is_constructible_object_type
: is_constructible_object_type_impl<BasicJsonType, : is_constructible_object_type_impl<BasicJsonType,
ConstructibleObjectType> {}; ConstructibleObjectType> {};
template<typename BasicJsonType, typename CompatibleStringType,
typename = void>
struct is_compatible_string_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleStringType> template<typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type_impl < struct is_compatible_string_type
BasicJsonType, CompatibleStringType,
enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
range_value_t,
CompatibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
}; };
template<typename BasicJsonType, typename ConstructibleStringType> template<typename BasicJsonType, typename ConstructibleStringType>
struct is_compatible_string_type struct is_constructible_string_type
: is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
template<typename BasicJsonType, typename ConstructibleStringType,
typename = void>
struct is_constructible_string_type_impl : std::false_type {};
template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type_impl <
BasicJsonType, ConstructibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
value_type_t, ConstructibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
is_constructible<ConstructibleStringType, is_constructible<ConstructibleStringType,
typename BasicJsonType::string_t>::value; typename BasicJsonType::string_t>::value;
}; };
template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type
: is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
template<typename BasicJsonType, typename CompatibleArrayType, typename = void> template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {}; struct is_compatible_array_type_impl : std::false_type {};
...@@ -3829,7 +3806,10 @@ struct is_compatible_array_type_impl < ...@@ -3829,7 +3806,10 @@ struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType, BasicJsonType, CompatibleArrayType,
enable_if_t < enable_if_t <
is_detected<iterator_t, CompatibleArrayType>::value&& is_detected<iterator_t, CompatibleArrayType>::value&&
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value >> is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
// special case for types like std::filesystem::path whose iterator's value_type are themselves
// c.f. https://github.com/nlohmann/json/pull/3073
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
{ {
static constexpr bool value = static constexpr bool value =
is_constructible<BasicJsonType, is_constructible<BasicJsonType,
...@@ -3862,8 +3842,11 @@ struct is_constructible_array_type_impl < ...@@ -3862,8 +3842,11 @@ struct is_constructible_array_type_impl <
is_detected<iterator_t, ConstructibleArrayType>::value&& is_detected<iterator_t, ConstructibleArrayType>::value&&
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
is_detected<range_value_t, ConstructibleArrayType>::value&& is_detected<range_value_t, ConstructibleArrayType>::value&&
is_complete_type < // special case for types like std::filesystem::path whose iterator's value_type are themselves
detected_t<range_value_t, ConstructibleArrayType >>::value >> // c.f. https://github.com/nlohmann/json/pull/3073
!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
is_complete_type <
detected_t<range_value_t, ConstructibleArrayType >>::value >>
{ {
using value_type = range_value_t<ConstructibleArrayType>; using value_type = range_value_t<ConstructibleArrayType>;
...@@ -3967,6 +3950,10 @@ T conditional_static_cast(U value) ...@@ -3967,6 +3950,10 @@ T conditional_static_cast(U value)
// #include <nlohmann/detail/value_t.hpp> // #include <nlohmann/detail/value_t.hpp>
#ifdef JSON_HAS_CPP_17
#include <filesystem>
#endif
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
...@@ -4117,7 +4104,7 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l) ...@@ -4117,7 +4104,7 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l)
} }
template<typename BasicJsonType, typename T, std::size_t N> template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void()) -> decltype(j.template get<T>(), void())
{ {
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
...@@ -4392,6 +4379,18 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE ...@@ -4392,6 +4379,18 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE
} }
} }
#ifdef JSON_HAS_CPP_17
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, std::filesystem::path& p)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j));
}
p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
#endif
struct from_json_fn struct from_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
...@@ -4425,6 +4424,8 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va ...@@ -4425,6 +4424,8 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
// #include <nlohmann/detail/macro_scope.hpp>
// #include <nlohmann/detail/iterators/iteration_proxy.hpp> // #include <nlohmann/detail/iterators/iteration_proxy.hpp>
...@@ -4625,6 +4626,10 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> ...@@ -4625,6 +4626,10 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
// #include <nlohmann/detail/value_t.hpp> // #include <nlohmann/detail/value_t.hpp>
#ifdef JSON_HAS_CPP_17
#include <filesystem>
#endif
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
...@@ -4997,6 +5002,14 @@ void to_json(BasicJsonType& j, const T& t) ...@@ -4997,6 +5002,14 @@ void to_json(BasicJsonType& j, const T& t)
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
} }
#ifdef JSON_HAS_CPP_17
template<typename BasicJsonType>
void to_json(BasicJsonType& j, const std::filesystem::path& p)
{
j = p.string();
}
#endif
struct to_json_fn struct to_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment