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_integer | 2147483648..9223372036854775807 | int64 | 0x12 |
| number_unsigned | 0..2147483647 | int32 | 0x10 | | number_unsigned | 0..2147483647 | int32 | 0x10 |
| number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 | | number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 |
| number_unsigned | 9223372036854775808..18446744073709551615 | -- | -- | | number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | 0x11 |
| number_float | *any value* | double | 0x01 | | number_float | *any value* | double | 0x01 |
| string | *any value* | string | 0x02 | | string | *any value* | string | 0x02 |
| array | *any value* | document | 0x04 | | array | *any value* | document | 0x04 |
@ -73,7 +73,7 @@ The library maps BSON record types to JSON value types as follows:
| Symbol | 0x0E | *unsupported* | | Symbol | 0x0E | *unsupported* |
| JavaScript Code | 0x0F | *unsupported* | | JavaScript Code | 0x0F | *unsupported* |
| int32 | 0x10 | number_integer | | int32 | 0x10 | number_integer |
| Timestamp | 0x11 | *unsupported* | | uint64(Timestamp) | 0x11 | number_unsigned |
| 128-bit decimal float | 0x13 | *unsupported* | | 128-bit decimal float | 0x13 | *unsupported* |
| Max Key | 0x7F | *unsupported* | | Max Key | 0x7F | *unsupported* |
| Min Key | 0xFF | *unsupported* | | Min Key | 0xFF | *unsupported* |
@ -94,3 +94,8 @@ The library maps BSON record types to JSON value types as follows:
```json ```json
--8<-- "examples/from_bson.output" --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 ### 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" !!! 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); 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) default: // anything else not supported (yet)
{ {
std::array<char, 3> cr{{}}; std::array<char, 3> cr{{}};

View File

@ -1097,7 +1097,8 @@ class binary_writer
} }
else 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); 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) default: // anything else not supported (yet)
{ {
std::array<char, 3> cr{{}}; std::array<char, 3> cr{{}};
@ -16733,7 +16739,8 @@ class binary_writer
} }
else 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") 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 = json const j =
{ {
{ "entry", std::uint64_t{0x1234567804030201} } { "entry", std::uint64_t{0x1234567804030201} }
@ -531,7 +530,6 @@ TEST_CASE("BSON")
SECTION("Some more complex document") SECTION("Some more complex document")
{ {
// directly encoding uint64 is not supported in bson (only for timestamp values)
json const j = json const j =
{ {
{"double", 42.5}, {"double", 42.5},
@ -1164,10 +1162,7 @@ TEST_CASE("BSON numerical data")
std::vector<std::uint64_t> const numbers std::vector<std::uint64_t> const numbers
{ {
static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1ULL, static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()) + 1ULL,
10000000000000000000ULL, 0xffffffffffffffff,
18000000000000000000ULL,
(std::numeric_limits<std::uint64_t>::max)() - 1ULL,
(std::numeric_limits<std::uint64_t>::max)(),
}; };
for (const auto i : numbers) for (const auto i : numbers)
@ -1184,7 +1179,7 @@ TEST_CASE("BSON numerical data")
std::vector<std::uint8_t> const expected_bson = std::vector<std::uint8_t> const expected_bson =
{ {
0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
0x12u, /// entry: int64 0x11u, /// entry: uint64
'e', 'n', 't', 'r', 'y', '\x00', 'e', 'n', 't', 'r', 'y', '\x00',
static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu), static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu), static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
@ -1197,12 +1192,15 @@ TEST_CASE("BSON numerical data")
0x00u // end marker 0x00u // end marker
}; };
CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&); const auto bson = json::to_bson(j);
#if JSON_DIAGNOSTICS CHECK(bson == expected_bson);
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 auto j_roundtrip = json::from_bson(bson);
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 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);
} }
} }