1
0
mirror of https://github.com/nlohmann/json.git synced 2025-07-31 10:24:23 +03:00

Add binary type support to all binary file formats, as well as an internally represented binary type

This commit is contained in:
Michael Reilly
2019-07-05 00:13:25 -04:00
parent 6121fc52cf
commit 012c9665ac
21 changed files with 3008 additions and 106 deletions

View File

@ -97,6 +97,9 @@ default; will be used in @ref number_integer_t)
`uint64_t` by default; will be used in @ref number_unsigned_t)
@tparam NumberFloatType type for JSON floating-point numbers (`double` by
default; will be used in @ref number_float_t)
@tparam BinaryType type for packed binary data for compatibility with binary
serialization formats (`std::vector<std::uint8_t>` by default; will be used in
@ref binary_t)
@tparam AllocatorType type of the allocator to use (`std::allocator` by
default)
@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
@ -818,6 +821,85 @@ class basic_json
*/
using number_float_t = NumberFloatType;
/*!
@brief a type for a packed binary type
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
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).
[CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type
as:
> Major type 2: a byte string. The string's length in bytes is
> represented following the rules for positive integers (major type
> 0).
[MessagePack's documentation on the bin type
family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family)
describes this type as:
> Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes
> in addition to the size of the byte array.
[BSON's specifications](http://bsonspec.org/spec.html) describe several
binary types; however, this type is intended to represent the generic binary
type which has the description:
> Generic binary subtype - This is the most commonly used binary subtype and
> should be the 'default' for drivers and tools.
None of these impose any limitations on the internal representation other
than the basic unit of storage be some type of array whose parts are
decomposible into bytes.
The default representation of this binary format is a
`std::vector<std::uint8_t>`, which is a very common way to represent a byte
array in modern C++.
#### Default type
The default values for @a BinaryType is `std::vector<std::uint8_t>`
#### Storage
Binary Arrays are stored as pointers in a @ref basic_json type. That is,
for any access to array values, a pointer of the type `binary_t*` must be
dereferenced.
@sa @ref array_t -- type for an array value
@since version 3.8.0
*/
using binary_t = BinaryType;
/*!
@brief an internal type for a backed binary type
This type is designed to be `binary_t` but with the subtype implementation
detail. This type exists so that the user does not have to specify a struct
his- or herself with a specific naming scheme in order to override the
binary type. I.e. it's for ease of use.
*/
struct internal_binary_t : public BinaryType
{
using BinaryType::BinaryType;
internal_binary_t() : BinaryType() {}
internal_binary_t(BinaryType const& bint) : BinaryType(bint) {}
internal_binary_t(BinaryType&& bint) : BinaryType(std::move(bint)) {}
// TOOD: If minimum C++ version is ever bumped to C++17, this field
// deserves to be a std::optional
std::uint8_t subtype = 0;
bool has_subtype = false;
};
/// @}
private:
@ -860,6 +942,7 @@ class basic_json
number | number_integer | @ref number_integer_t
number | number_unsigned | @ref number_unsigned_t
number | number_float | @ref number_float_t
binary | binary | pointer to @ref internal_binary_t
null | null | *no value is stored*
@note Variable-length types (objects, arrays, and strings) are stored as
@ -876,6 +959,8 @@ class basic_json
array_t* array;
/// string (stored with pointer to save storage)
string_t* string;
/// binary (stored with pointer to save storage)
internal_binary_t* binary;
/// boolean
boolean_t boolean;
/// number (integer)
@ -918,6 +1003,12 @@ class basic_json
break;
}
case value_t::binary:
{
binary = create<internal_binary_t>();
break;
}
case value_t::boolean:
{
boolean = boolean_t(false);
@ -996,6 +1087,18 @@ class basic_json
array = create<array_t>(std::move(value));
}
/// constructor for binary arrays
json_value(const binary_t& value)
{
binary = create<internal_binary_t>(value);
}
/// constructor for rvalue binary arrays
json_value(binary_t&& value)
{
binary = create<internal_binary_t>(std::move(value));
}
void destroy(value_t t) noexcept
{
// flatten the current json_value to a heap-allocated stack
@ -1071,6 +1174,14 @@ class basic_json
break;
}
case value_t::binary:
{
AllocatorType<internal_binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
break;
}
default:
{
break;
@ -1191,6 +1302,7 @@ class basic_json
number | `0`
object | `{}`
array | `[]`
binary | empty array
@param[in] v the type of the value to create
@ -1262,6 +1374,12 @@ class basic_json
@ref number_float_t, and all convertible number types such as `int`,
`size_t`, `int64_t`, `float` or `double` can be used.
- **boolean**: @ref boolean_t / `bool` can be used.
- **binary**: @ref binary_t / `std::vector<uint8_t>` may be used,
unfortunately because string literals cannot be distinguished from binary
character arrays by the C++ type system, all types compatible with `const
char*` will be directed to the string constructor instead. This is both
for backwards compatibility, and due to the fact that a binary type is not
a standard JSON type.
See the examples below.
@ -1343,6 +1461,7 @@ class basic_json
using other_string_t = typename BasicJsonType::string_t;
using other_object_t = typename BasicJsonType::object_t;
using other_array_t = typename BasicJsonType::array_t;
using other_binary_t = typename BasicJsonType::internal_binary_t;
switch (val.type())
{
@ -1367,6 +1486,9 @@ class basic_json
case value_t::array:
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
break;
case value_t::binary:
JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
break;
case value_t::null:
*this = nullptr;
break;
@ -1505,6 +1627,78 @@ class basic_json
assert_invariant();
}
/*!
@brief explicitly create a binary array from an already constructed copy of
its base type
Creates a JSON binary array value from a given `binary_t`. Binary values are
part of various binary formats, such as CBOR, MsgPack, and BSON. And this
constructor is used to create a value for serialization to those formats.
@note Note, this function exists because of the difficulty in correctly
specifying the correct template overload in the standard value ctor, as both
JSON arrays and JSON binary arrays are backed with some form of a
`std::vector`. Because JSON binary arrays are a non-standard extension it
was decided that it would be best to prevent automatic initialization of a
binary array type, for backwards compatibility and so it does not happen on
accident.
@param[in] init `binary_t` with JSON values to create a binary array from
@return JSON binary array value
@complexity Linear in the size of @a init.
@exceptionsafety Strong guarantee: if an exception is thrown, there are no
changes to any JSON value.
@since version 3.8.0
*/
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json binary_array(binary_t const& init)
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = init;
return res;
}
/*!
@brief explicitly create a binary array from an already constructed rvalue
copy of its base type
Creates a JSON binary array value from a given `binary_t`. Binary values are
part of various binary formats, such as CBOR, MsgPack, and BSON. And this
constructor is used to create a value for serialization to those formats.
@note Note, this function exists because of the difficulty in correctly
specifying the correct template overload in the standard value ctor, as both
JSON arrays and JSON binary arrays are backed with some form of a
`std::vector`. Because JSON binary arrays are a non-standard extension it
was decided that it would be best to prevent automatic initialization of a
binary array type, for backwards compatibility and so it doesn't happen on
accident.
@param[in] init `binary_t` with JSON values to create a binary array from
@return JSON binary array value
@complexity Linear in the size of @a init.
@exceptionsafety Strong guarantee: if an exception is thrown, there are no
changes to any JSON value.
@since version 3.8.0
*/
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json binary_array(binary_t&& init)
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = std::move(init);
return res;
}
/*!
@brief explicitly create an array from an initializer list
@ -1760,6 +1954,13 @@ class basic_json
break;
}
case value_t::binary:
{
m_value.binary = create<internal_binary_t>(first.m_it.binary_iterator,
last.m_it.binary_iterator);
break;
}
default:
JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
std::string(first.m_object->type_name())));
@ -1853,6 +2054,12 @@ class basic_json
break;
}
case value_t::binary:
{
m_value = *other.m_value.binary;
break;
}
default:
break;
}
@ -1993,6 +2200,11 @@ class basic_json
possible values: `strict` (throws and exception in case a decoding error
occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),
and `ignore` (ignore invalid UTF-8 sequences during serialization).
@param[in] serialize_binary Whether or not to allow serialization of binary
types to JSON. Because binary types are non-standard, this will produce
non-conformant JSON, and is disabled by default. This flag is primarily
useful for debugging. Will output the binary value as a list of 8-bit
numbers prefixed by "b" (e.g. "bindata" = b[3, 0, 42, 255]).
@return string containing the serialization of the JSON value
@ -2017,18 +2229,19 @@ class basic_json
string_t dump(const int indent = -1,
const char indent_char = ' ',
const bool ensure_ascii = false,
const error_handler_t error_handler = error_handler_t::strict) const
const error_handler_t error_handler = error_handler_t::strict,
const bool serialize_binary = false) const
{
string_t result;
serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
if (indent >= 0)
{
s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent), serialize_binary);
}
else
{
s.dump(*this, false, ensure_ascii, 0);
s.dump(*this, false, ensure_ascii, 0, serialize_binary);
}
return result;
@ -2051,6 +2264,7 @@ class basic_json
number (floating-point) | value_t::number_float
object | value_t::object
array | value_t::array
binary | value_t::binary
discarded | value_t::discarded
@complexity Constant.
@ -2093,12 +2307,13 @@ class basic_json
@sa @ref is_string() -- returns whether JSON value is a string
@sa @ref is_boolean() -- returns whether JSON value is a boolean
@sa @ref is_number() -- returns whether JSON value is a number
@sa @ref is_binary() -- returns whether JSON value is a binary array
@since version 1.0.0
*/
constexpr bool is_primitive() const noexcept
{
return is_null() or is_string() or is_boolean() or is_number();
return is_null() or is_string() or is_boolean() or is_number() or is_binary();
}
/*!
@ -2353,6 +2568,28 @@ class basic_json
return m_type == value_t::string;
}
/*!
@brief return whether value is a binary array
This function returns true if and only if the JSON value is a binary array.
@return `true` if type is binary array, `false` otherwise.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@liveexample{The following code exemplifies `is_binary()` for all JSON
types.,is_binary}
@since version 3.8.0
*/
constexpr bool is_binary() const noexcept
{
return m_type == value_t::binary;
}
/*!
@brief return whether value is discarded
@ -2508,6 +2745,18 @@ class basic_json
return is_number_float() ? &m_value.number_float : nullptr;
}
/// get a pointer to the value (binary)
binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
{
return is_binary() ? m_value.binary : nullptr;
}
/// get a pointer to the value (binary)
constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
{
return is_binary() ? m_value.binary : nullptr;
}
/*!
@brief helper function to implement get_ref()
@ -3555,6 +3804,120 @@ class basic_json
return value(ptr, string_t(default_value));
}
/*!
@brief return the binary subtype
Returns the numerical subtype of the JSON value, if the JSON value is of
type "binary", and it has a subtype. If it does not have a subtype (or the
object is not of type binary) this function will return size_t(-1) as a
sentinel value.
@return the numerical subtype of the binary JSON value
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@sa @ref set_subtype() -- sets the binary subtype
@sa @ref clear_subtype() -- clears the binary subtype
@sa @ref has_subtype() -- returns whether or not the binary value has a
subtype
@since version 3.8.0
*/
std::size_t get_subtype() const noexcept
{
if (is_binary() and m_value.binary->has_subtype)
{
return m_value.binary->subtype;
}
return std::size_t(-1);
}
/*!
@brief sets the binary subtype
Sets the binary subtype of the JSON value, also flags a binary JSON value as
having a subtype, which has implications for serialization to msgpack (will
prefer ext file formats over bin). If the JSON value is not a binary value,
this function does nothing.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@sa @ref get_subtype() -- return the binary subtype
@sa @ref clear_subtype() -- clears the binary subtype
@sa @ref has_subtype() -- returns whether or not the binary value has a
subtype
@since version 3.8.0
*/
void set_subtype(std::uint8_t subtype) noexcept
{
if (is_binary())
{
m_value.binary->has_subtype = true;
m_value.binary->subtype = subtype;
}
}
/*!
@brief clears the binary subtype
Clears the binary subtype of the JSON value, also flags a binary JSON value
as not having a subtype, which has implications for serialization to msgpack
(will prefer bin file formats over ext). If the JSON value is not a binary
value, this function does nothing.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@sa @ref get_subtype() -- return the binary subtype
@sa @ref set_subtype() -- sets the binary subtype
@sa @ref has_subtype() -- returns whether or not the binary value has a
subtype
@since version 3.8.0
*/
void clear_subtype() noexcept
{
if (is_binary())
{
m_value.binary->has_subtype = false;
m_value.binary->subtype = 0;
}
}
/*!
@brief return whether or not the binary subtype has a value
Returns whether or not the binary subtype has a value.
@return whether or not the binary subtype has a value.
@complexity Constant.
@exceptionsafety No-throw guarantee: this member function never throws
exceptions.
@sa @ref get_subtype() -- return the binary subtype
@sa @ref set_subtype() -- sets the binary subtype
@sa @ref clear_subtype() -- clears the binary subtype
@since version 3.8.0
*/
bool has_subtype() const noexcept
{
return is_binary() and m_value.binary->has_subtype;
}
/*!
@brief access the first element
@ -3562,8 +3925,8 @@ class basic_json
container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
@return In case of a structured type (array or object), a reference to the
first element is returned. In case of number, string, or boolean values, a
reference to the value is returned.
first element is returned. In case of number, string, boolean, or binary
values, a reference to the value is returned.
@complexity Constant.
@ -3605,8 +3968,8 @@ class basic_json
@endcode
@return In case of a structured type (array or object), a reference to the
last element is returned. In case of number, string, or boolean values, a
reference to the value is returned.
last element is returned. In case of number, string, boolean, or binary
values, a reference to the value is returned.
@complexity Constant.
@ -3672,7 +4035,7 @@ class basic_json
@complexity The complexity depends on the type:
- objects: amortized constant
- arrays: linear in distance between @a pos and the end of the container
- strings: linear in the length of the string
- strings and binary: linear in the length of the member
- other types: constant
@liveexample{The example shows the result of `erase()` for different JSON
@ -3708,6 +4071,7 @@ class basic_json
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::string:
case value_t::binary:
{
if (JSON_HEDLEY_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
{
@ -3721,6 +4085,13 @@ class basic_json
std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
m_value.string = nullptr;
}
else if (is_binary())
{
AllocatorType<internal_binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
m_value.binary = nullptr;
}
m_type = value_t::null;
assert_invariant();
@ -3778,7 +4149,7 @@ class basic_json
- objects: `log(size()) + std::distance(first, last)`
- arrays: linear in the distance between @a first and @a last, plus linear
in the distance between @a last and end of the container
- strings: linear in the length of the string
- strings and binary: linear in the length of the member
- other types: constant
@liveexample{The example shows the result of `erase()` for different JSON
@ -3813,6 +4184,7 @@ class basic_json
case value_t::number_integer:
case value_t::number_unsigned:
case value_t::string:
case value_t::binary:
{
if (JSON_HEDLEY_LIKELY(not first.m_it.primitive_iterator.is_begin()
or not last.m_it.primitive_iterator.is_end()))
@ -3827,6 +4199,13 @@ class basic_json
std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
m_value.string = nullptr;
}
else if (is_binary())
{
AllocatorType<internal_binary_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
m_value.binary = nullptr;
}
m_type = value_t::null;
assert_invariant();
@ -4546,6 +4925,7 @@ class basic_json
boolean | `false`
string | `false`
number | `false`
binary | `false`
object | result of function `object_t::empty()`
array | result of function `array_t::empty()`
@ -4617,6 +4997,7 @@ class basic_json
boolean | `1`
string | `1`
number | `1`
binary | `1`
object | result of function object_t::size()
array | result of function array_t::size()
@ -4691,6 +5072,7 @@ class basic_json
boolean | `1` (same as `size()`)
string | `1` (same as `size()`)
number | `1` (same as `size()`)
binary | `1` (same as `size()`)
object | result of function `object_t::max_size()`
array | result of function `array_t::max_size()`
@ -4763,6 +5145,7 @@ class basic_json
boolean | `false`
string | `""`
number | `0`
binary | An empty byte vector
object | `{}`
array | `[]`
@ -4820,6 +5203,12 @@ class basic_json
break;
}
case value_t::binary:
{
m_value.binary->clear();
break;
}
case value_t::array:
{
m_value.array->clear();
@ -5696,6 +6085,9 @@ class basic_json
case value_t::number_float:
return lhs.m_value.number_float == rhs.m_value.number_float;
case value_t::binary:
return *lhs.m_value.binary == *rhs.m_value.binary;
default:
return false;
}
@ -5856,6 +6248,9 @@ class basic_json
case value_t::number_float:
return (lhs.m_value.number_float) < (rhs.m_value.number_float);
case value_t::binary:
return (lhs.m_value.binary) < (rhs.m_value.binary);
default:
return false;
}
@ -6420,6 +6815,7 @@ class basic_json
number | `"number"` (for all number types)
object | `"object"`
array | `"array"`
binary | `"binary"`
discarded | `"discarded"`
@exceptionsafety No-throw guarantee: this function never throws exceptions.
@ -6451,6 +6847,8 @@ class basic_json
return "string";
case value_t::boolean:
return "boolean";
case value_t::binary:
return "binary";
case value_t::discarded:
return "discarded";
default:
@ -6526,6 +6924,11 @@ class basic_json
object | *size*: 256..65535 | map (2 bytes follow) | 0xB9
object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA
object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB
binary | *size*: 0..23 | byte string | 0x40..0x57
binary | *size*: 23..255 | byte string (1 byte follow) | 0x58
binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59
binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A
binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B
@note The mapping is **complete** in the sense that any JSON value type
can be converted to a CBOR value.
@ -6535,10 +6938,10 @@ class basic_json
function which serializes NaN or Infinity to `null`.
@note The following CBOR types are not used in the conversion:
- byte strings (0x40..0x5F)
- UTF-8 strings terminated by "break" (0x7F)
- arrays terminated by "break" (0x9F)
- maps terminated by "break" (0xBF)
- byte strings terminated by "break" (0x5F)
- date/time (0xC0..0xC1)
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
@ -6625,20 +7028,21 @@ class basic_json
object | *size*: 0..15 | fix map | 0x80..0x8F
object | *size*: 16..65535 | map 16 | 0xDE
object | *size*: 65536..4294967295 | map 32 | 0xDF
binary | *size*: 0..255 | bin 8 | 0xC4
binary | *size*: 256..65535 | bin 16 | 0xC5
binary | *size*: 65536..4294967295 | bin 32 | 0xC6
@note The mapping is **complete** in the sense that any JSON value type
can be converted to a MessagePack value.
@note The following values can **not** be converted to a MessagePack value:
- strings with more than 4294967295 bytes
- byte strings with more than 4294967295 bytes
- arrays with more than 4294967295 elements
- objects with more than 4294967295 elements
@note The following MessagePack types are not used in the conversion:
- bin 8 - bin 32 (0xC4..0xC6)
- ext 8 - ext 32 (0xC7..0xC9)
- float 32 (0xCA)
- fixext 1 - fixext 16 (0xD4..0xD8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@ -6741,6 +7145,12 @@ class basic_json
the benefit of this parameter is that the receiving side is
immediately informed on the number of elements of the container.
@note If the JSON data contains the binary type, the value stored is a list
of integers, as suggested by the UBJSON documentation. In particular,
this means that serialization and the deserialization of a JSON
containing binary values into UBJSON and back will result in a
different JSON object.
@param[in] j JSON value to serialize
@param[in] use_size whether to add size annotations to container types
@param[in] use_type whether to add type annotations to container types
@ -6805,6 +7215,7 @@ class basic_json
string | *any value* | string | 0x02
array | *any value* | document | 0x04
object | *any value* | document | 0x03
binary | *any value* | binary | 0x05
@warning The mapping is **incomplete**, since only JSON-objects (and things
contained therein) can be serialized to BSON.
@ -6886,7 +7297,11 @@ class basic_json
Negative integer | number_integer | 0x39
Negative integer | number_integer | 0x3A
Negative integer | number_integer | 0x3B
Negative integer | number_integer | 0x40..0x57
Byte string | binary | 0x40..0x57
Byte string | binary | 0x58
Byte string | binary | 0x59
Byte string | binary | 0x5A
Byte string | binary | 0x5B
UTF-8 string | string | 0x60..0x77
UTF-8 string | string | 0x78
UTF-8 string | string | 0x79
@ -6915,7 +7330,6 @@ class basic_json
@warning The mapping is **incomplete** in the sense that not all CBOR
types can be converted to a JSON value. The following CBOR types
are not supported and will yield parse errors (parse_error.112):
- byte strings (0x40..0x5F)
- date/time (0xC0..0xC1)
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
@ -7026,15 +7440,19 @@ class basic_json
array 32 | array | 0xDD
map 16 | object | 0xDE
map 32 | object | 0xDF
bin 8 | binary | 0xC4
bin 16 | binary | 0xC5
bin 32 | binary | 0xC6
ext 8 | binary | 0xC7
ext 16 | binary | 0xC8
ext 32 | binary | 0xC9
fixext 1 | binary | 0xD4
fixext 2 | binary | 0xD5
fixext 4 | binary | 0xD6
fixext 8 | binary | 0xD7
fixext 16 | binary | 0xD8
negative fixint | number_integer | 0xE0-0xFF
@warning The mapping is **incomplete** in the sense that not all
MessagePack types can be converted to a JSON value. The following
MessagePack types are not supported and will yield parse errors:
- bin 8 - bin 32 (0xC4..0xC6)
- ext 8 - ext 32 (0xC7..0xC9)
- fixext 1 - fixext 16 (0xD4..0xD8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.