diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 5f497089..8955ee7a 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -227,8 +227,8 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.subtype); + result.m_has_subtype = true; // All BSON binary values have a subtype + get_number(input_format_t::bson, result.m_subtype); return get_binary(input_format_t::bson, len, result); } @@ -1524,58 +1524,58 @@ class binary_reader case 0xC7: // ext 8 { std::uint8_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC8: // ext 16 { std::uint16_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC9: // ext 32 { std::uint32_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xD4: // fixext 1 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); } case 0xD5: // fixext 2 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); } case 0xD6: // fixext 4 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); } case 0xD7: // fixext 8 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); } case 0xD8: // fixext 16 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); } default: // LCOV_EXCL_LINE diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 7d4a4031..39935d10 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -550,7 +550,7 @@ class binary_writer { // step 0: determine if the binary type has a set subtype to // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_value.binary->has_subtype; + const bool use_ext = j.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length const auto N = j.m_value.binary->size(); @@ -630,7 +630,9 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype); + std::uint8_t subtype; + write_number(subtype); + j.m_value.binary->set_subtype(subtype); } // step 2: write the byte string @@ -1085,12 +1087,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - std::uint8_t subtype = 0x00; // Generic Binary Subtype - if (value.has_subtype) - { - subtype = value.subtype; - } - write_number(subtype); + write_number(value.has_subtype() ? value.subtype() : 0x00); oa->write_characters(reinterpret_cast(value.data()), value.size()); } diff --git a/include/nlohmann/detail/wrapped_binary_t.hpp b/include/nlohmann/detail/wrapped_binary_t.hpp index 1ec6a98a..8514f049 100644 --- a/include/nlohmann/detail/wrapped_binary_t.hpp +++ b/include/nlohmann/detail/wrapped_binary_t.hpp @@ -17,8 +17,13 @@ his- or herself with a specific naming scheme in order to override the binary type. I.e. it's for ease of use. */ template -struct wrapped_binary_t : public BinaryType +class wrapped_binary_t : public BinaryType { + public: + // to simplify code in binary_reader + template + friend class binary_reader; + using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) @@ -36,18 +41,56 @@ struct wrapped_binary_t : public BinaryType wrapped_binary_t(const binary_t& bint, std::uint8_t st) noexcept(noexcept(binary_t(bint))) : binary_t(bint) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) : binary_t(std::move(bint)) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} - std::uint8_t subtype = 0; - bool has_subtype = false; + /*! + @brief set the subtype + @param subtype subtype to set (implementation specific) + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief get the subtype + @return subtype (implementation specific) + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief get whether a subtype was set + @return whether a subtype was set + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clear the subtype + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; }; } // namespace detail diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index e9650165..21becba4 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -839,15 +839,15 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and - BSON's generic binary subtype. This type is NOT a part of standard JSON and + BSON's generic binary subtype. This type is NOT a part of standard JSON and exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is - carried around as a `unint8_t`, which is compatible with both of the binary - data formats that use binary subtyping, (though the specific numbering is - incompatible with each other, and it is up to the user to translate between - them). + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: @@ -890,6 +890,18 @@ class basic_json */ using binary_t = BinaryType; + /*! + @brief binary array with a binary type + + This type is used to store binary types internally. It wrapps the template + type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish + different binary types from different formats. + + While @ref binary_t is used to define how binary values are stored, this + type is used to access binary values once they are parsed. + + @sa @ref binary_array -- create a binary array + */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} @@ -3882,8 +3894,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = true; - m_value.binary->subtype = subtype; + m_value.binary->set_subtype(subtype); } } @@ -3911,8 +3922,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = false; - m_value.binary->subtype = 0; + m_value.binary->clear_subtype(); } } @@ -3936,7 +3946,7 @@ class basic_json */ bool has_subtype() const noexcept { - return is_binary() and m_value.binary->has_subtype; + return is_binary() and m_value.binary->has_subtype(); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2d12e895..8b01d241 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5804,8 +5804,8 @@ class binary_reader return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); } - result.has_subtype = true; // All BSON binary values have a subtype - get_number(input_format_t::bson, result.subtype); + result.m_has_subtype = true; // All BSON binary values have a subtype + get_number(input_format_t::bson, result.m_subtype); return get_binary(input_format_t::bson, len, result); } @@ -7101,58 +7101,58 @@ class binary_reader case 0xC7: // ext 8 { std::uint8_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC8: // ext 16 { std::uint16_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xC9: // ext 32 { std::uint32_t len; - result.has_subtype = true; + result.m_has_subtype = true; return get_number(input_format_t::msgpack, len) and - get_number(input_format_t::msgpack, result.subtype) and + get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, len, result); } case 0xD4: // fixext 1 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result); } case 0xD5: // fixext 2 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result); } case 0xD6: // fixext 4 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result); } case 0xD7: // fixext 8 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result); } case 0xD8: // fixext 16 { - result.has_subtype = true; - return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); + result.m_has_subtype = true; + return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result); } default: // LCOV_EXCL_LINE @@ -12557,7 +12557,7 @@ class binary_writer { // step 0: determine if the binary type has a set subtype to // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_value.binary->has_subtype; + const bool use_ext = j.m_value.binary->has_subtype(); // step 1: write control byte and the byte string length const auto N = j.m_value.binary->size(); @@ -12637,7 +12637,9 @@ class binary_writer // step 1.5: if this is an ext type, write the subtype if (use_ext) { - write_number(j.m_value.binary->subtype); + std::uint8_t subtype; + write_number(subtype); + j.m_value.binary->set_subtype(subtype); } // step 2: write the byte string @@ -13092,12 +13094,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - std::uint8_t subtype = 0x00; // Generic Binary Subtype - if (value.has_subtype) - { - subtype = value.subtype; - } - write_number(subtype); + write_number(value.has_subtype() ? value.subtype() : 0x00); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -15593,8 +15590,13 @@ his- or herself with a specific naming scheme in order to override the binary type. I.e. it's for ease of use. */ template -struct wrapped_binary_t : public BinaryType +class wrapped_binary_t : public BinaryType { + public: + // to simplify code in binary_reader + template + friend class binary_reader; + using binary_t = BinaryType; wrapped_binary_t() noexcept(noexcept(binary_t())) @@ -15612,18 +15614,56 @@ struct wrapped_binary_t : public BinaryType wrapped_binary_t(const binary_t& bint, std::uint8_t st) noexcept(noexcept(binary_t(bint))) : binary_t(bint) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) : binary_t(std::move(bint)) - , subtype(st) - , has_subtype(true) + , m_subtype(st) + , m_has_subtype(true) {} - std::uint8_t subtype = 0; - bool has_subtype = false; + /*! + @brief set the subtype + @param subtype subtype to set (implementation specific) + */ + void set_subtype(std::uint8_t subtype) noexcept + { + m_subtype = subtype; + m_has_subtype = true; + } + + /*! + @brief get the subtype + @return subtype (implementation specific) + */ + constexpr std::uint8_t subtype() const noexcept + { + return m_subtype; + } + + /*! + @brief get whether a subtype was set + @return whether a subtype was set + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clear the subtype + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + std::uint8_t m_subtype = 0; + bool m_has_subtype = false; }; } // namespace detail @@ -16398,15 +16438,15 @@ class basic_json This type is a type designed to carry binary data that appears in various serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and - BSON's generic binary subtype. This type is NOT a part of standard JSON and + BSON's generic binary subtype. This type is NOT a part of standard JSON and exists solely for compatibility with these binary types. As such, it is simply defined as an ordered sequence of zero or more byte values. Additionally, as an implementation detail, the subtype of the binary data is - carried around as a `unint8_t`, which is compatible with both of the binary - data formats that use binary subtyping, (though the specific numbering is - incompatible with each other, and it is up to the user to translate between - them). + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type as: @@ -16449,6 +16489,18 @@ class basic_json */ using binary_t = BinaryType; + /*! + @brief binary array with a binary type + + This type is used to store binary types internally. It wrapps the template + type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish + different binary types from different formats. + + While @ref binary_t is used to define how binary values are stored, this + type is used to access binary values once they are parsed. + + @sa @ref binary_array -- create a binary array + */ using internal_binary_t = nlohmann::detail::wrapped_binary_t; /// @} @@ -19441,8 +19493,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = true; - m_value.binary->subtype = subtype; + m_value.binary->set_subtype(subtype); } } @@ -19470,8 +19521,7 @@ class basic_json { if (is_binary()) { - m_value.binary->has_subtype = false; - m_value.binary->subtype = 0; + m_value.binary->clear_subtype(); } } @@ -19495,7 +19545,7 @@ class basic_json */ bool has_subtype() const noexcept { - return is_binary() and m_value.binary->has_subtype; + return is_binary() and m_value.binary->has_subtype(); } /*!