mirror of
https://github.com/nlohmann/json.git
synced 2025-07-29 23:01:16 +03:00
Support BSON uint64 de/serialization (#4590)
* 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:
committed by
GitHub
parent
1809b3d800
commit
2d42229f4d
@ -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.
|
@ -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"
|
||||||
|
|
||||||
|
@ -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{{}};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user