mirror of
https://github.com/nlohmann/json.git
synced 2025-08-07 18:02:57 +03:00
* Specialize char_traits for std::byte to fix from_msgpack (fixes #4756) Provide a char_traits<std::byte> specialization under __cpp_lib_byte to allow parsing MessagePack data from containers of std::byte. Signed-off-by: xuesongtap <tap91624@gmail.com> Signed-off-by: yexiaochuan <tap91624@gmail.com> * Fix comments for cstddef include and MessagePack tests Signed-off-by: xuesongtap <tap91624@gmail.com> Signed-off-by: yexiaochuan <tap91624@gmail.com> * Fix include <cstddef> only when __cpp_lib_byte is defined and sufficient Signed-off-by: yexiaochuan <tap91624@gmail.com> * Fix clang-tidy warnings in MessagePack std::byte tests Signed-off-by: yexiaochuan <tap91624@gmail.com> * Fix handle return value in MessagePack tests Signed-off-by: yexiaochuan <tap91624@gmail.com> --------- Signed-off-by: xuesongtap <tap91624@gmail.com> Signed-off-by: yexiaochuan <tap91624@gmail.com>
This commit is contained in:
@@ -13,7 +13,9 @@
|
|||||||
#include <tuple> // tuple
|
#include <tuple> // tuple
|
||||||
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||||
#include <utility> // declval
|
#include <utility> // declval
|
||||||
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
|
#include <cstddef> // byte
|
||||||
|
#endif
|
||||||
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
#include <nlohmann/detail/meta/call_std/begin.hpp>
|
#include <nlohmann/detail/meta/call_std/begin.hpp>
|
||||||
@@ -239,6 +241,30 @@ struct char_traits<signed char> : std::char_traits<char>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
|
template<>
|
||||||
|
struct char_traits<std::byte> : std::char_traits<char>
|
||||||
|
{
|
||||||
|
using char_type = std::byte;
|
||||||
|
using int_type = uint64_t;
|
||||||
|
|
||||||
|
static int_type to_int_type(char_type c) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(std::to_integer<unsigned char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_type to_char_type(int_type i) noexcept
|
||||||
|
{
|
||||||
|
return std::byte(static_cast<unsigned char>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int_type eof() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(std::char_traits<char>::eof());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
// is_ functions //
|
// is_ functions //
|
||||||
///////////////////
|
///////////////////
|
||||||
|
@@ -3367,7 +3367,9 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
#include <tuple> // tuple
|
#include <tuple> // tuple
|
||||||
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||||
#include <utility> // declval
|
#include <utility> // declval
|
||||||
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
|
#include <cstddef> // byte
|
||||||
|
#endif
|
||||||
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
|
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||||
// __ _____ _____ _____
|
// __ _____ _____ _____
|
||||||
// __| | __| | | | JSON for Modern C++
|
// __| | __| | | | JSON for Modern C++
|
||||||
@@ -3776,6 +3778,30 @@ struct char_traits<signed char> : std::char_traits<char>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
|
template<>
|
||||||
|
struct char_traits<std::byte> : std::char_traits<char>
|
||||||
|
{
|
||||||
|
using char_type = std::byte;
|
||||||
|
using int_type = uint64_t;
|
||||||
|
|
||||||
|
static int_type to_int_type(char_type c) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(std::to_integer<unsigned char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_type to_char_type(int_type i) noexcept
|
||||||
|
{
|
||||||
|
return std::byte(static_cast<unsigned char>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int_type eof() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(std::char_traits<char>::eof());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
// is_ functions //
|
// is_ functions //
|
||||||
///////////////////
|
///////////////////
|
||||||
|
@@ -1880,3 +1880,80 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
// Test suite for verifying MessagePack handling with std::byte input
|
||||||
|
TEST_CASE("MessagePack with std::byte")
|
||||||
|
{
|
||||||
|
|
||||||
|
SECTION("std::byte compatibility")
|
||||||
|
{
|
||||||
|
SECTION("vector roundtrip")
|
||||||
|
{
|
||||||
|
json original =
|
||||||
|
{
|
||||||
|
{"name", "test"},
|
||||||
|
{"value", 42},
|
||||||
|
{"array", {1, 2, 3}}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint8_t> temp = json::to_msgpack(original);
|
||||||
|
// Convert the uint8_t vector to std::byte vector
|
||||||
|
std::vector<std::byte> msgpack_data(temp.size());
|
||||||
|
for (size_t i = 0; i < temp.size(); ++i)
|
||||||
|
{
|
||||||
|
msgpack_data[i] = std::byte(temp[i]);
|
||||||
|
}
|
||||||
|
// Deserialize from std::byte vector back to JSON
|
||||||
|
json from_bytes;
|
||||||
|
CHECK_NOTHROW(from_bytes = json::from_msgpack(msgpack_data));
|
||||||
|
|
||||||
|
CHECK(from_bytes == original);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("empty vector")
|
||||||
|
{
|
||||||
|
const std::vector<std::byte> empty_data;
|
||||||
|
CHECK_THROWS_WITH_AS([&]() {
|
||||||
|
[[maybe_unused]] auto result = json::from_msgpack(empty_data);
|
||||||
|
return true;
|
||||||
|
}(),
|
||||||
|
"[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input",
|
||||||
|
json::parse_error&);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("comparison with workaround")
|
||||||
|
{
|
||||||
|
json original =
|
||||||
|
{
|
||||||
|
{"string", "hello"},
|
||||||
|
{"integer", 42},
|
||||||
|
{"float", 3.14},
|
||||||
|
{"boolean", true},
|
||||||
|
{"null", nullptr},
|
||||||
|
{"array", {1, 2, 3}},
|
||||||
|
{"object", {{"key", "value"}}}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint8_t> temp = json::to_msgpack(original);
|
||||||
|
|
||||||
|
std::vector<std::byte> msgpack_data(temp.size());
|
||||||
|
for (size_t i = 0; i < temp.size(); ++i)
|
||||||
|
{
|
||||||
|
msgpack_data[i] = std::byte(temp[i]);
|
||||||
|
}
|
||||||
|
// Attempt direct deserialization using std::byte input
|
||||||
|
json direct_result = json::from_msgpack(msgpack_data);
|
||||||
|
|
||||||
|
// Test the workaround approach: reinterpret as unsigned char* and use iterator range
|
||||||
|
const auto *const char_start = reinterpret_cast<unsigned char const*>(msgpack_data.data());
|
||||||
|
const auto *const char_end = char_start + msgpack_data.size();
|
||||||
|
json workaround_result = json::from_msgpack(char_start, char_end);
|
||||||
|
|
||||||
|
// Verify that the final deserialized JSON matches the original JSON
|
||||||
|
CHECK(direct_result == workaround_result);
|
||||||
|
CHECK(direct_result == original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Reference in New Issue
Block a user