From 5ce7d6bdd7dc28d8d9e8f6d3bc91b541217bdb5d Mon Sep 17 00:00:00 2001 From: Julian Becker Date: Sat, 15 Sep 2018 13:03:42 +0200 Subject: [PATCH] BSON: support objects with objects as members --- .../nlohmann/detail/input/binary_reader.hpp | 9 +++++- .../nlohmann/detail/output/binary_writer.hpp | 17 ++++++++++- single_include/nlohmann/json.hpp | 26 +++++++++++++++-- test/src/unit-bson.cpp | 29 +++++++++++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index d135a4c2..7deb788a 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -231,10 +231,17 @@ class binary_reader sax->null(); } break; + case 0x03: // object + { + string_t key; + get_bson_cstr(key); + sax->key(key); + parse_bson_internal(); + } + break; } } - get(); const auto result = sax->end_object(); return result; diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 770c7dd3..1ec1d794 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -775,6 +775,18 @@ class binary_writer } } + std::size_t write_bson_object_internal(const typename BasicJsonType::string_t& name, const BasicJsonType& j) + { + oa->write_character(static_cast(0x03)); // object + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + auto const embedded_document_size = write_bson_object(j); + + return /*id*/ 1ul + name.size() + 1ul + embedded_document_size; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -782,6 +794,8 @@ class binary_writer default: JSON_THROW(type_error::create(317, "JSON value cannot be serialized to requested format")); break; + case value_t::object: + return write_bson_object_internal(name, j); case value_t::boolean: return write_bson_boolean(name, j); case value_t::number_float: @@ -803,7 +817,7 @@ class binary_writer @param[in] j JSON value to serialize @pre j.type() == value_t::object */ - void write_bson_object(const BasicJsonType& j) + std::size_t write_bson_object(const BasicJsonType& j) { assert(j.type() == value_t::object); auto document_size_offset = oa->reserve_characters(4ul); @@ -816,6 +830,7 @@ class binary_writer oa->write_character(static_cast(0x00)); write_number_little_endian_at(document_size_offset, document_size); + return document_size; } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index fa1d8e39..6201f047 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -6215,10 +6215,17 @@ class binary_reader sax->null(); } break; + case 0x03: // object + { + string_t key; + get_bson_cstr(key); + sax->key(key); + parse_bson_internal(); + } + break; } } - get(); const auto result = sax->end_object(); return result; @@ -8609,6 +8616,18 @@ class binary_writer } } + std::size_t write_bson_object_internal(const typename BasicJsonType::string_t& name, const BasicJsonType& j) + { + oa->write_character(static_cast(0x03)); // object + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + auto const embedded_document_size = write_bson_object(j); + + return /*id*/ 1ul + name.size() + 1ul + embedded_document_size; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -8616,6 +8635,8 @@ class binary_writer default: JSON_THROW(type_error::create(317, "JSON value cannot be serialized to requested format")); break; + case value_t::object: + return write_bson_object_internal(name, j); case value_t::boolean: return write_bson_boolean(name, j); case value_t::number_float: @@ -8637,7 +8658,7 @@ class binary_writer @param[in] j JSON value to serialize @pre j.type() == value_t::object */ - void write_bson_object(const BasicJsonType& j) + std::size_t write_bson_object(const BasicJsonType& j) { assert(j.type() == value_t::object); auto document_size_offset = oa->reserve_characters(4ul); @@ -8650,6 +8671,7 @@ class binary_writer oa->write_character(static_cast(0x00)); write_number_little_endian_at(document_size_offset, document_size); + return document_size; } /*! diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 8de05e80..bdc6fe74 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -351,5 +351,34 @@ TEST_CASE("BSON") CHECK(json::from_bson(result) == j); CHECK(json::from_bson(result, true, false) == j); } + + SECTION("non-empty object with object member") + { + // directly encoding uint64 is not supported in bson (only for timestamp values) + json j = + { + { "entry", json::object() } + }; + + std::vector expected = + { + 0x11, 0x00, 0x00, 0x00, // size (little endian) + 0x03, /// entry: embedded document + 'e', 'n', 't', 'r', 'y', '\x00', + + 0x05, 0x00, 0x00, 0x00, // size (little endian) + // no entries + 0x00, // end marker (embedded document) + + 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); + } } }