diff --git a/README.md b/README.md index eebf86df..0572199f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ - [JSON Merge Patch](#json-merge-patch) - [Implicit conversions](#implicit-conversions) - [Conversions to/from arbitrary types](#arbitrary-types-conversions) - - [Binary formats (CBOR, MessagePack, and UBJSON)](#binary-formats-cbor-messagepack-and-ubjson) + - [Binary formats (CBOR, BSON, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson) - [Supported compilers](#supported-compilers) - [License](#license) - [Contact](#contact) @@ -874,14 +874,22 @@ struct bad_serializer }; ``` -### Binary formats (CBOR, MessagePack, and UBJSON) +### Binary formats (CBOR, BSON, MessagePack, and UBJSON -Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors. +Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supportsĀ [BSON](http://bsonspec.org) (Binary JSON), [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors. ```cpp // create a JSON value json j = R"({"compact": true, "schema": 0})"_json; +// serialize to BSON +std::vector v_bson = json::to_bson(j); + +// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +// roundtrip +json j_from_bson = json::from_bson(v_bson); + // serialize to CBOR std::vector v_cbor = json::to_cbor(j); @@ -1138,6 +1146,8 @@ I deeply appreciate the help of the following people. - [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. - [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. - [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. +- [efp](https://github.com/efp) added line and column information to parse errors. +- [julian-becker](https://github.com/julian-becker) added BSON support. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 64a02aac..27833ab6 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -875,10 +875,11 @@ class binary_writer static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) { std::size_t embedded_document_size = 0ul; + std::size_t array_index = 0ul; for (const auto& el : value) { - embedded_document_size += calc_bson_element_size("", el); + embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el); } return sizeof(std::int32_t) + embedded_document_size + 1ul; @@ -893,9 +894,11 @@ class binary_writer write_bson_entry_header(name, 0x04); // array write_number(static_cast(calc_bson_array_size(value))); + std::size_t array_index = 0ul; + for (const auto& el : value) { - write_bson_element("", el); + write_bson_element(std::to_string(array_index++), el); } oa->write_character(static_cast(0x00)); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cdd4e680..c9060781 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -9155,10 +9155,11 @@ class binary_writer static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) { std::size_t embedded_document_size = 0ul; + std::size_t array_index = 0ul; for (const auto& el : value) { - embedded_document_size += calc_bson_element_size("", el); + embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el); } return sizeof(std::int32_t) + embedded_document_size + 1ul; @@ -9173,9 +9174,11 @@ class binary_writer write_bson_entry_header(name, 0x04); // array write_number(static_cast(calc_bson_array_size(value))); + std::size_t array_index = 0ul; + for (const auto& el : value) { - write_bson_element("", el); + write_bson_element(std::to_string(array_index++), el); } oa->write_character(static_cast(0x00)); diff --git a/test/data/json.org/1.json.bson b/test/data/json.org/1.json.bson index e14e9b92..a2466af8 100644 Binary files a/test/data/json.org/1.json.bson and b/test/data/json.org/1.json.bson differ diff --git a/test/data/json.org/2.json.bson b/test/data/json.org/2.json.bson index 0f4356e1..743822c5 100644 Binary files a/test/data/json.org/2.json.bson and b/test/data/json.org/2.json.bson differ diff --git a/test/data/json.org/3.json.bson b/test/data/json.org/3.json.bson index deb7c539..2c43e351 100644 Binary files a/test/data/json.org/3.json.bson and b/test/data/json.org/3.json.bson differ diff --git a/test/data/json.org/4.json.bson b/test/data/json.org/4.json.bson index 31812125..aceba2d8 100644 Binary files a/test/data/json.org/4.json.bson and b/test/data/json.org/4.json.bson differ diff --git a/test/data/json.org/5.json.bson b/test/data/json.org/5.json.bson index a3be9240..b72643da 100644 Binary files a/test/data/json.org/5.json.bson and b/test/data/json.org/5.json.bson differ diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 711e8a64..5a16aefd 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -483,19 +483,19 @@ TEST_CASE("BSON") std::vector expected = { - 0x41, 0x00, 0x00, 0x00, // size (little endian) + 0x49, 0x00, 0x00, 0x00, // size (little endian) 0x04, /// entry: embedded document 'e', 'n', 't', 'r', 'y', '\x00', - 0x35, 0x00, 0x00, 0x00, // size (little endian) - 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0x00, 0x00, // size (little endian) + 0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00, + 0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00, + 0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00, + 0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00, + 0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, // end marker (embedded document) 0x00 // end marker @@ -552,6 +552,7 @@ TEST_CASE("BSON") CHECK(parsed == expected); auto dumped = json::to_bson(parsed); CHECK(dumped == input); + CHECK(json::from_bson(dumped) == expected); } SECTION("Example 2") @@ -561,7 +562,7 @@ TEST_CASE("BSON") json expected = {{"BSON", {"awesome", 5.05, 1986}}}; CHECK(parsed == expected); auto dumped = json::to_bson(parsed); - //CHECK(dumped == input); // see https://github.com/nlohmann/json/pull/1254#issuecomment-432831216 + CHECK(dumped == input); CHECK(json::from_bson(dumped) == expected); } } @@ -1225,7 +1226,14 @@ TEST_CASE("BSON roundtrips", "[hide]") { std::vector vec; json::to_bson(j1, vec); - CHECK(vec == packed); + + if (vec != packed) + { + // the exact serializations may differ due to the order of + // object keys; in these cases, just compare whether both + // serializations create the same JSON value + CHECK(json::from_bson(vec) == json::from_bson(packed)); + } } } }