Support BSON uint64 de/serialization (#4590)
Some checks failed
Code scanning - action / CodeQL-Build (push) Has been cancelled
macOS / macos-13 (14.1) (push) Has been cancelled
macOS / macos-13 (14.2) (push) Has been cancelled
macOS / macos-13 (14.3) (push) Has been cancelled
macOS / macos-13 (14.3.1) (push) Has been cancelled
macOS / macos-13 (15.0.1) (push) Has been cancelled
macOS / macos-13 (15.1) (push) Has been cancelled
macOS / macos-13 (15.2) (push) Has been cancelled
macOS / macos-14 (15.3) (push) Has been cancelled
macOS / macos-14 (15.4) (push) Has been cancelled
macOS / macos-15 (16.0) (push) Has been cancelled
macOS / macos-15 (16.1) (push) Has been cancelled
macOS / xcode_standards (11) (push) Has been cancelled
macOS / xcode_standards (14) (push) Has been cancelled
macOS / xcode_standards (17) (push) Has been cancelled
macOS / xcode_standards (20) (push) Has been cancelled
macOS / xcode_standards (23) (push) Has been cancelled
Publish documentation / publish_documentation (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Ubuntu / ci_test_clang (push) Has been cancelled
Ubuntu / ci_test_gcc (push) Has been cancelled
Ubuntu / ci_infer (push) Has been cancelled
Ubuntu / ci_test_single_header (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_cppcheck) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_cpplint) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_non_git_tests) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_offline_testdata) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_reproducible_tests) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_reuse_compliance) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_test_amalgamation) (push) Has been cancelled
Ubuntu / ci_static_analysis_ubuntu (ci_test_valgrind) (push) Has been cancelled
Ubuntu / ci_static_analysis_clang (ci_clang_analyze) (push) Has been cancelled
Ubuntu / ci_static_analysis_clang (ci_clang_tidy) (push) Has been cancelled
Ubuntu / ci_static_analysis_clang (ci_single_binaries) (push) Has been cancelled
Ubuntu / ci_static_analysis_clang (ci_test_clang_sanitizer) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_cmake_flags) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_diagnostic_positions) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_diagnostics) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_legacycomparison) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_noexceptions) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_noglobaludls) (push) Has been cancelled
Ubuntu / ci_cmake_options (ci_test_noimplicitconversions) (push) Has been cancelled
Ubuntu / ci_test_coverage (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc_old (4.8) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc_old (4.9) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc_old (5) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc_old (6) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (10) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (11) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (12) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (13) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (14) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (7) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (8) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (9) (push) Has been cancelled
Ubuntu / ci_test_compilers_gcc (latest) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (10) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (11) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (12) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (13) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (14) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (15-bullseye) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (16) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (17) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (18) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (19) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (3.5) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (3.6) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (3.7) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (3.8) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (3.9) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (4) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (5) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (6) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (7) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (8) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (9) (push) Has been cancelled
Ubuntu / ci_test_compilers_clang (latest) (push) Has been cancelled
Ubuntu / ci_test_standards_gcc (11) (push) Has been cancelled
Ubuntu / ci_test_standards_gcc (14) (push) Has been cancelled
Ubuntu / ci_test_standards_gcc (17) (push) Has been cancelled
Ubuntu / ci_test_standards_gcc (20) (push) Has been cancelled
Ubuntu / ci_test_standards_gcc (23) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (11, libcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (11, libstdcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (14, libcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (14, libstdcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (17, libcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (17, libstdcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (20, libcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (20, libstdcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (23, libcxx) (push) Has been cancelled
Ubuntu / ci_test_standards_clang (23, libstdcxx) (push) Has been cancelled
Ubuntu / ci_cuda_example (push) Has been cancelled
Ubuntu / ci_icpc (push) Has been cancelled
Ubuntu / ci_test_documentation (ci_test_build_documentation) (push) Has been cancelled
Ubuntu / ci_test_documentation (ci_test_examples) (push) Has been cancelled
Windows / mingw (x64) (push) Has been cancelled
Windows / mingw (x86) (push) Has been cancelled
Windows / msvc2019 (Win32, Debug) (push) Has been cancelled
Windows / msvc2019 (Win32, Release) (push) Has been cancelled
Windows / msvc2019 (x64, Debug) (push) Has been cancelled
Windows / msvc2019 (x64, Release) (push) Has been cancelled
Windows / msvc2019_latest (push) Has been cancelled
Windows / msvc2022 (Win32, Debug) (push) Has been cancelled
Windows / msvc2022 (Win32, Release) (push) Has been cancelled
Windows / msvc2022 (x64, Debug) (push) Has been cancelled
Windows / msvc2022 (x64, Release) (push) Has been cancelled
Windows / msvc2022_latest (push) Has been cancelled
Windows / clang (11) (push) Has been cancelled
Windows / clang (12) (push) Has been cancelled
Windows / clang (13) (push) Has been cancelled
Windows / clang (14) (push) Has been cancelled
Windows / clang (15) (push) Has been cancelled
Windows / clang-cl-11 (Win32) (push) Has been cancelled
Windows / clang-cl-11 (x64) (push) Has been cancelled

* Support BSON uint64 de/serialization

Signed-off-by: Michael Valladolid <mikevalladolid@gmail.com>

* Treat 0x11 as uint64 and not timestamp specific

Signed-off-by: Michael Valladolid <mikevalladolid@gmail.com>

---------

Signed-off-by: Michael Valladolid <mikevalladolid@gmail.com>
This commit is contained in:
Michael Valladolid 2025-01-10 22:59:55 +09:00 committed by GitHub
parent 1809b3d800
commit 2d42229f4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 35 additions and 18 deletions

View File

@ -23,7 +23,7 @@ The library uses the following mapping from JSON values types to BSON types:
| number_integer | 2147483648..9223372036854775807 | int64 | 0x12 |
| number_unsigned | 0..2147483647 | int32 | 0x10 |
| number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 |
| number_unsigned | 9223372036854775808..18446744073709551615 | -- | -- |
| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | 0x11 |
| number_float | *any value* | double | 0x01 |
| string | *any value* | string | 0x02 |
| array | *any value* | document | 0x04 |
@ -73,7 +73,7 @@ The library maps BSON record types to JSON value types as follows:
| Symbol | 0x0E | *unsupported* |
| JavaScript Code | 0x0F | *unsupported* |
| int32 | 0x10 | number_integer |
| Timestamp | 0x11 | *unsupported* |
| uint64(Timestamp) | 0x11 | number_unsigned |
| 128-bit decimal float | 0x13 | *unsupported* |
| Max Key | 0x7F | *unsupported* |
| Min Key | 0xFF | *unsupported* |
@ -94,3 +94,8 @@ The library maps BSON record types to JSON value types as follows:
```json
--8<-- "examples/from_bson.output"
```
!!! note "Handling of BSON type 0x11"
BSON type 0x11 is used to represent uint64 numbers. This library treats these values purely as uint64 numbers
and does not parse them into date-related formats.

View File

@ -839,7 +839,7 @@ A parsed number could not be stored as without changing it to NaN or INF.
### json.exception.out_of_range.407
UBJSON and BSON only support integer numbers up to 9223372036854775807.
UBJSON only support integer numbers up to 9223372036854775807.
!!! failure "Example message"

View File

@ -328,6 +328,12 @@ class binary_reader
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
}
case 0x11: // uint64
{
std::uint64_t value{};
return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value);
}
default: // anything else not supported (yet)
{
std::array<char, 3> cr{{}};

View File

@ -1097,7 +1097,8 @@ class binary_writer
}
else
{
JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
write_bson_entry_header(name, 0x11 /* uint64 */);
write_number<std::uint64_t>(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned), true);
}
}

View File

@ -10006,6 +10006,12 @@ class binary_reader
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
}
case 0x11: // uint64
{
std::uint64_t value{};
return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value);
}
default: // anything else not supported (yet)
{
std::array<char, 3> cr{{}};
@ -16733,7 +16739,8 @@ class binary_writer
}
else
{
JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
write_bson_entry_header(name, 0x11 /* uint64 */);
write_number<std::uint64_t>(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned), true);
}
}

View File

@ -331,7 +331,6 @@ TEST_CASE("BSON")
SECTION("non-empty object with unsigned integer (64-bit) member")
{
// directly encoding uint64 is not supported in bson (only for timestamp values)
json const j =
{
{ "entry", std::uint64_t{0x1234567804030201} }
@ -531,7 +530,6 @@ TEST_CASE("BSON")
SECTION("Some more complex document")
{
// directly encoding uint64 is not supported in bson (only for timestamp values)
json const j =
{
{"double", 42.5},
@ -1164,10 +1162,7 @@ TEST_CASE("BSON numerical data")
std::vector<std::uint64_t> const numbers
{
static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1ULL,
10000000000000000000ULL,
18000000000000000000ULL,
(std::numeric_limits<std::uint64_t>::max)() - 1ULL,
(std::numeric_limits<std::uint64_t>::max)(),
0xffffffffffffffff,
};
for (const auto i : numbers)
@ -1184,7 +1179,7 @@ TEST_CASE("BSON numerical data")
std::vector<std::uint8_t> const expected_bson =
{
0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
0x12u, /// entry: int64
0x11u, /// entry: uint64
'e', 'n', 't', 'r', 'y', '\x00',
static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
@ -1197,12 +1192,15 @@ TEST_CASE("BSON numerical data")
0x00u // end marker
};
CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
#if JSON_DIAGNOSTICS
CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] (/entry) integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
#else
CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
#endif
const auto bson = json::to_bson(j);
CHECK(bson == expected_bson);
auto j_roundtrip = json::from_bson(bson);
CHECK(j.at("entry").is_number_unsigned());
CHECK(j_roundtrip.at("entry").is_number_unsigned());
CHECK(j_roundtrip == j);
CHECK(json::from_bson(bson, true, false) == j);
}
}