mirror of https://github.com/nlohmann/json.git
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 #3070pull/3079/head^2
parent
4b1cb9eee1
commit
0e694b4060
|
@ -19,6 +19,10 @@
|
|||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
|
@ -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
|
||||
{
|
||||
template<typename BasicJsonType, typename T>
|
||||
|
|
|
@ -9,11 +9,16 @@
|
|||
#include <valarray> // valarray
|
||||
#include <vector> // vector
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
|
@ -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> {});
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
template<typename BasicJsonType, typename T>
|
||||
|
|
|
@ -309,44 +309,21 @@ struct is_constructible_object_type
|
|||
: is_constructible_object_type_impl<BasicJsonType,
|
||||
ConstructibleObjectType> {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleStringType,
|
||||
typename = void>
|
||||
struct is_compatible_string_type_impl : std::false_type {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleStringType>
|
||||
struct is_compatible_string_type_impl <
|
||||
BasicJsonType, CompatibleStringType,
|
||||
enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
|
||||
range_value_t,
|
||||
CompatibleStringType>::value >>
|
||||
struct is_compatible_string_type
|
||||
{
|
||||
static constexpr auto value =
|
||||
is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleStringType>
|
||||
struct is_compatible_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 >>
|
||||
struct is_constructible_string_type
|
||||
{
|
||||
static constexpr auto value =
|
||||
is_constructible<ConstructibleStringType,
|
||||
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>
|
||||
struct is_compatible_array_type_impl : std::false_type {};
|
||||
|
||||
|
@ -355,7 +332,10 @@ struct is_compatible_array_type_impl <
|
|||
BasicJsonType, CompatibleArrayType,
|
||||
enable_if_t <
|
||||
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 =
|
||||
is_constructible<BasicJsonType,
|
||||
|
@ -388,6 +368,9 @@ struct is_constructible_array_type_impl <
|
|||
is_detected<iterator_t, ConstructibleArrayType>::value&&
|
||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
|
||||
is_detected<range_value_t, ConstructibleArrayType>::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<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
|
||||
is_complete_type <
|
||||
detected_t<range_value_t, ConstructibleArrayType >>::value >>
|
||||
{
|
||||
|
|
|
@ -3783,44 +3783,21 @@ struct is_constructible_object_type
|
|||
: is_constructible_object_type_impl<BasicJsonType,
|
||||
ConstructibleObjectType> {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleStringType,
|
||||
typename = void>
|
||||
struct is_compatible_string_type_impl : std::false_type {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleStringType>
|
||||
struct is_compatible_string_type_impl <
|
||||
BasicJsonType, CompatibleStringType,
|
||||
enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
|
||||
range_value_t,
|
||||
CompatibleStringType>::value >>
|
||||
struct is_compatible_string_type
|
||||
{
|
||||
static constexpr auto value =
|
||||
is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleStringType>
|
||||
struct is_compatible_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 >>
|
||||
struct is_constructible_string_type
|
||||
{
|
||||
static constexpr auto value =
|
||||
is_constructible<ConstructibleStringType,
|
||||
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>
|
||||
struct is_compatible_array_type_impl : std::false_type {};
|
||||
|
||||
|
@ -3829,7 +3806,10 @@ struct is_compatible_array_type_impl <
|
|||
BasicJsonType, CompatibleArrayType,
|
||||
enable_if_t <
|
||||
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 =
|
||||
is_constructible<BasicJsonType,
|
||||
|
@ -3862,6 +3842,9 @@ struct is_constructible_array_type_impl <
|
|||
is_detected<iterator_t, ConstructibleArrayType>::value&&
|
||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
|
||||
is_detected<range_value_t, ConstructibleArrayType>::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<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
|
||||
is_complete_type <
|
||||
detected_t<range_value_t, ConstructibleArrayType >>::value >>
|
||||
{
|
||||
|
@ -3967,6 +3950,10 @@ T conditional_static_cast(U value)
|
|||
// #include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
|
@ -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
|
||||
{
|
||||
template<typename BasicJsonType, typename T>
|
||||
|
@ -4425,6 +4424,8 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va
|
|||
#include <valarray> // valarray
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
|
||||
|
||||
|
||||
|
@ -4625,6 +4626,10 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
|
|||
// #include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
|
@ -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> {});
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
template<typename BasicJsonType, typename T>
|
||||
|
|
|
@ -37,8 +37,8 @@ SOFTWARE.
|
|||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
#include <list>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
@ -47,6 +47,7 @@ using ordered_json = nlohmann::ordered_json;
|
|||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <filesystem>
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
|
@ -69,14 +70,19 @@ using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool
|
|||
/////////////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
struct NonDefaultFromJsonStruct { };
|
||||
struct NonDefaultFromJsonStruct
|
||||
{};
|
||||
|
||||
inline bool operator==(NonDefaultFromJsonStruct const& /*unused*/, NonDefaultFromJsonStruct const& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class for_1647 { one, two };
|
||||
enum class for_1647
|
||||
{
|
||||
one,
|
||||
two
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
|
||||
|
@ -93,7 +99,10 @@ NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
|
|||
struct Data
|
||||
{
|
||||
Data() = default;
|
||||
Data(std::string a_, std::string b_) : a(std::move(a_)), b(std::move(b_)) {}
|
||||
Data(std::string a_, std::string b_)
|
||||
: a(std::move(a_))
|
||||
, b(std::move(b_))
|
||||
{}
|
||||
std::string a{};
|
||||
std::string b{};
|
||||
};
|
||||
|
@ -138,14 +147,15 @@ struct NotSerializableData
|
|||
float myfloat;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2574
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NonDefaultConstructible
|
||||
{
|
||||
explicit NonDefaultConstructible (int a) : x(a) { }
|
||||
explicit NonDefaultConstructible(int a)
|
||||
: x(a)
|
||||
{}
|
||||
int x;
|
||||
};
|
||||
|
||||
|
@ -168,7 +178,9 @@ struct adl_serializer<NonDefaultConstructible>
|
|||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
{
|
||||
public:
|
||||
explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser<json>(j, false) {}
|
||||
explicit sax_no_exception(json& j)
|
||||
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
|
||||
{}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
{
|
||||
|
@ -296,9 +308,12 @@ TEST_CASE("regression tests 2")
|
|||
using it_type = decltype(p1.begin());
|
||||
|
||||
std::set_difference(
|
||||
p1.begin(), p1.end(),
|
||||
p2.begin(), p2.end(),
|
||||
std::inserter(diffs, diffs.end()), [&](const it_type & e1, const it_type & e2) -> bool
|
||||
p1.begin(),
|
||||
p1.end(),
|
||||
p2.begin(),
|
||||
p2.end(),
|
||||
std::inserter(diffs, diffs.end()),
|
||||
[&](const it_type & e1, const it_type & e2) -> bool
|
||||
{
|
||||
using comper_pair = std::pair<std::string, decltype(e1.value())>; // Trying to avoid unneeded copy
|
||||
return comper_pair(e1.key(), e1.value()) < comper_pair(e2.key(), e2.value()); // Using pair comper
|
||||
|
@ -311,7 +326,8 @@ TEST_CASE("regression tests 2")
|
|||
SECTION("issue #1292 - Serializing std::variant causes stack overflow")
|
||||
{
|
||||
static_assert(
|
||||
!std::is_constructible<json, std::variant<int, float>>::value, "");
|
||||
!std::is_constructible<json, std::variant<int, float>>::value,
|
||||
"");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -376,24 +392,7 @@ TEST_CASE("regression tests 2")
|
|||
nlohmann::json dump_test;
|
||||
const std::array<int, 108> data =
|
||||
{
|
||||
{
|
||||
109, 108, 103, 125, -122, -53, 115,
|
||||
18, 3, 0, 102, 19, 1, 15,
|
||||
-110, 13, -3, -1, -81, 32, 2,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
8, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, -80, 2,
|
||||
0, 0, 96, -118, 46, -116, 46,
|
||||
109, -84, -87, 108, 14, 109, -24,
|
||||
-83, 13, -18, -51, -83, -52, -115,
|
||||
14, 6, 32, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
64, 3, 0, 0, 0, 35, -74,
|
||||
-73, 55, 57, -128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 33, 0, 0, 0, -96,
|
||||
-54, -28, -26
|
||||
}
|
||||
{109, 108, 103, 125, -122, -53, 115, 18, 3, 0, 102, 19, 1, 15, -110, 13, -3, -1, -81, 32, 2, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -80, 2, 0, 0, 96, -118, 46, -116, 46, 109, -84, -87, 108, 14, 109, -24, -83, 13, -18, -51, -83, -52, -115, 14, 6, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 0, 0, 0, 35, -74, -73, 55, 57, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, -96, -54, -28, -26}
|
||||
};
|
||||
std::string s;
|
||||
for (int i : data)
|
||||
|
@ -495,8 +494,7 @@ TEST_CASE("regression tests 2")
|
|||
' ', // Indent char
|
||||
false, // Ensure ascii
|
||||
json::error_handler_t::strict // Error
|
||||
)
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
SECTION("PR #2181 - regression bug with lvalue")
|
||||
|
@ -512,7 +510,16 @@ TEST_CASE("regression tests 2")
|
|||
{
|
||||
std::vector<uint8_t> data =
|
||||
{
|
||||
0x7B, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x4F, 0x42
|
||||
0x7B,
|
||||
0x6F,
|
||||
0x62,
|
||||
0x6A,
|
||||
0x65,
|
||||
0x63,
|
||||
0x74,
|
||||
0x20,
|
||||
0x4F,
|
||||
0x42
|
||||
};
|
||||
json result = json::from_cbor(data, true, false);
|
||||
CHECK(result.is_discarded());
|
||||
|
@ -566,7 +573,6 @@ TEST_CASE("regression tests 2")
|
|||
auto arr = j.get<std::array<NonDefaultConstructible, 2>>();
|
||||
CHECK(arr[0].x == 7);
|
||||
CHECK(arr[1].x == 4);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -695,6 +701,17 @@ TEST_CASE("regression tests 2")
|
|||
json k = json::from_cbor(my_vector);
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ")
|
||||
{
|
||||
std::filesystem::path text_path("/tmp/text.txt");
|
||||
json j(text_path);
|
||||
|
||||
const auto j_path = j.get<std::filesystem::path>();
|
||||
CHECK(j_path == text_path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
|
Loading…
Reference in New Issue