BSON: Support empty objects
This commit is contained in:
parent
f06c8fd8e3
commit
5f5836ce1c
4 changed files with 124 additions and 33 deletions
|
@ -127,25 +127,18 @@ class binary_reader
|
||||||
|
|
||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
int docLen = 0;
|
std::int32_t documentSize;
|
||||||
int byte;
|
get_number_little_endian(documentSize);
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
|
if (not JSON_UNLIKELY(sax->start_object(documentSize - 5)))
|
||||||
{
|
{
|
||||||
byte = get();
|
|
||||||
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
|
|
||||||
{
|
|
||||||
if (i == 1)
|
|
||||||
{
|
|
||||||
return sax->boolean(docLen != 0x00);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
docLen |= static_cast<std::int32_t>(byte) << 8 * i;
|
|
||||||
}
|
|
||||||
|
|
||||||
//sax->null();
|
const auto result = sax->end_object();
|
||||||
|
|
||||||
get();
|
get();
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -927,6 +920,35 @@ class binary_reader
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
bool get_number_little_endian(NumberType& result)
|
||||||
|
{
|
||||||
|
// step 1: read input into array with system's byte order
|
||||||
|
std::array<uint8_t, sizeof(NumberType)> vec;
|
||||||
|
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
|
||||||
|
{
|
||||||
|
get();
|
||||||
|
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse byte order prior to conversion if necessary
|
||||||
|
if (!is_little_endian)
|
||||||
|
{
|
||||||
|
vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 2: convert array into number of type T and return
|
||||||
|
std::memcpy(&result, vec.data(), sizeof(NumberType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a string by reading characters from the input
|
@brief create a string by reading characters from the input
|
||||||
|
|
||||||
|
|
|
@ -684,7 +684,8 @@ class binary_writer
|
||||||
void write_bson_object(const BasicJsonType& j)
|
void write_bson_object(const BasicJsonType& j)
|
||||||
{
|
{
|
||||||
assert(j.type() == value_t::object);
|
assert(j.type() == value_t::object);
|
||||||
|
write_number_little_endian(5);
|
||||||
|
oa->write_character(static_cast<CharType>(0x00));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -6068,25 +6068,18 @@ class binary_reader
|
||||||
|
|
||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
int docLen = 0;
|
std::int32_t documentSize;
|
||||||
int byte;
|
get_number_little_endian(documentSize);
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
|
if (not JSON_UNLIKELY(sax->start_object(documentSize - 5)))
|
||||||
{
|
{
|
||||||
byte = get();
|
|
||||||
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
|
|
||||||
{
|
|
||||||
if (i == 1)
|
|
||||||
{
|
|
||||||
return sax->boolean(docLen != 0x00);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
docLen |= static_cast<std::int32_t>(byte) << 8 * i;
|
|
||||||
}
|
|
||||||
|
|
||||||
//sax->null();
|
const auto result = sax->end_object();
|
||||||
|
|
||||||
get();
|
get();
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -6868,6 +6861,35 @@ class binary_reader
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
bool get_number_little_endian(NumberType& result)
|
||||||
|
{
|
||||||
|
// step 1: read input into array with system's byte order
|
||||||
|
std::array<uint8_t, sizeof(NumberType)> vec;
|
||||||
|
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
|
||||||
|
{
|
||||||
|
get();
|
||||||
|
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse byte order prior to conversion if necessary
|
||||||
|
if (!is_little_endian)
|
||||||
|
{
|
||||||
|
vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 2: convert array into number of type T and return
|
||||||
|
std::memcpy(&result, vec.data(), sizeof(NumberType));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a string by reading characters from the input
|
@brief create a string by reading characters from the input
|
||||||
|
|
||||||
|
@ -8354,7 +8376,8 @@ class binary_writer
|
||||||
void write_bson_object(const BasicJsonType& j)
|
void write_bson_object(const BasicJsonType& j)
|
||||||
{
|
{
|
||||||
assert(j.type() == value_t::object);
|
assert(j.type() == value_t::object);
|
||||||
|
write_number_little_endian(5);
|
||||||
|
oa->write_character(static_cast<CharType>(0x00));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -36,7 +36,7 @@ using nlohmann::json;
|
||||||
|
|
||||||
TEST_CASE("BSON")
|
TEST_CASE("BSON")
|
||||||
{
|
{
|
||||||
SECTION("individual values")
|
SECTION("individual values not supported")
|
||||||
{
|
{
|
||||||
SECTION("discarded")
|
SECTION("discarded")
|
||||||
{
|
{
|
||||||
|
@ -66,5 +66,50 @@ TEST_CASE("BSON")
|
||||||
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("number")
|
||||||
|
{
|
||||||
|
json j = 42;
|
||||||
|
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("float")
|
||||||
|
{
|
||||||
|
json j = 4.2;
|
||||||
|
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("string")
|
||||||
|
{
|
||||||
|
json j = "not supported";
|
||||||
|
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("array")
|
||||||
|
{
|
||||||
|
json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("objects")
|
||||||
|
{
|
||||||
|
SECTION("empty object")
|
||||||
|
{
|
||||||
|
json j = json::object();
|
||||||
|
std::vector<uint8_t> expected =
|
||||||
|
{
|
||||||
|
0x05, 0x00, 0x00, 0x00, // size (little endian)
|
||||||
|
// no entries
|
||||||
|
0x00 // end marker
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto result = json::to_bson(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_bson(result) == j);
|
||||||
|
CHECK(json::from_bson(result, true, false) == j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue