🔨 using input/output adapters for CBOR and MessagePack
- You can now pass a reference to a vector to the to_cbor and to_msgpack functions. The output will be written (appended) to the vector. #476 - You can now pass an output stream with uint8_t character type to the to_cbor and to_msgpack functions. #477 - You can now read from uint8_t */size in the to_cbor and to_msgpack functions. An input adapter will be created from this pair, so you need to use braces. #478
This commit is contained in:
parent
9b1c058810
commit
4414f94cd5
4 changed files with 168 additions and 47 deletions
90
src/json.hpp
90
src/json.hpp
|
@ -1443,8 +1443,15 @@ class input_adapter
|
||||||
: ia(std::make_shared<cached_input_stream_adapter<16384>>(i)) {}
|
: ia(std::make_shared<cached_input_stream_adapter<16384>>(i)) {}
|
||||||
|
|
||||||
/// input adapter for buffer
|
/// input adapter for buffer
|
||||||
input_adapter(const char* b, std::size_t l)
|
template <typename CharT,
|
||||||
: ia(std::make_shared<input_buffer_adapter>(b, l)) {}
|
typename std::enable_if<
|
||||||
|
std::is_pointer<CharT>::value and
|
||||||
|
std::is_integral<
|
||||||
|
typename std::remove_pointer<CharT>::type>::value and
|
||||||
|
sizeof(typename std::remove_pointer<CharT>::type) == 1,
|
||||||
|
int>::type = 0>
|
||||||
|
input_adapter(CharT b, std::size_t l)
|
||||||
|
: ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}
|
||||||
|
|
||||||
// derived support
|
// derived support
|
||||||
|
|
||||||
|
@ -4546,21 +4553,20 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
|
||||||
/// abstract output adapter interface
|
/// abstract output adapter interface
|
||||||
template <typename CharType> class output_adapter
|
template <typename CharType> struct output_adapter_protocol
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual void write_character(CharType c) = 0;
|
virtual void write_character(CharType c) = 0;
|
||||||
virtual void write_characters(const CharType* s, std::size_t length) = 0;
|
virtual void write_characters(const CharType* s, std::size_t length) = 0;
|
||||||
virtual ~output_adapter() = default;
|
virtual ~output_adapter_protocol() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// a type to simplify interfaces
|
/// a type to simplify interfaces
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
using output_adapter_t = std::shared_ptr<output_adapter<CharType>>;
|
using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
|
||||||
|
|
||||||
/// output adapter for byte vectors
|
/// output adapter for byte vectors
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
class output_vector_adapter : public output_adapter<CharType>
|
class output_vector_adapter : public output_adapter_protocol<CharType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
|
explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
|
||||||
|
@ -4581,7 +4587,7 @@ class output_vector_adapter : public output_adapter<CharType>
|
||||||
|
|
||||||
/// output adapter for output streams
|
/// output adapter for output streams
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
class output_stream_adapter : public output_adapter<CharType>
|
class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
|
explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
|
||||||
|
@ -4602,10 +4608,10 @@ class output_stream_adapter : public output_adapter<CharType>
|
||||||
|
|
||||||
/// output adapter for basic_string
|
/// output adapter for basic_string
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
class output_string_adapter : public output_adapter<CharType>
|
class output_string_adapter : public output_adapter_protocol<CharType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit output_string_adapter(std::string& s) : str(s) {}
|
explicit output_string_adapter(std::basic_string<CharType>& s) : str(s) {}
|
||||||
|
|
||||||
void write_character(CharType c) override
|
void write_character(CharType c) override
|
||||||
{
|
{
|
||||||
|
@ -4621,23 +4627,26 @@ class output_string_adapter : public output_adapter<CharType>
|
||||||
std::basic_string<CharType>& str;
|
std::basic_string<CharType>& str;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CharType> struct output_adapter_factory
|
template <typename CharType>
|
||||||
|
class output_adapter
|
||||||
{
|
{
|
||||||
static std::shared_ptr<output_adapter<CharType>>
|
public:
|
||||||
create(std::vector<CharType>& vec)
|
output_adapter(std::vector<CharType>& vec)
|
||||||
|
: oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
|
||||||
|
|
||||||
|
output_adapter(std::basic_ostream<CharType>& s)
|
||||||
|
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
|
||||||
|
|
||||||
|
output_adapter(std::basic_string<CharType>& s)
|
||||||
|
: oa(std::make_shared<output_string_adapter<CharType>>(s)) {}
|
||||||
|
|
||||||
|
operator output_adapter_t<CharType>()
|
||||||
{
|
{
|
||||||
return std::make_shared<output_vector_adapter<CharType>>(vec);
|
return oa;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<output_adapter<CharType>> create(std::ostream& s)
|
private:
|
||||||
{
|
output_adapter_t<CharType> oa = nullptr;
|
||||||
return std::make_shared<output_stream_adapter<CharType>>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::shared_ptr<output_adapter<CharType>> create(std::string& s)
|
|
||||||
{
|
|
||||||
return std::make_shared<output_string_adapter<CharType>>(s);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
@ -9109,7 +9118,7 @@ class basic_json
|
||||||
const bool ensure_ascii = false) const
|
const bool ensure_ascii = false) const
|
||||||
{
|
{
|
||||||
string_t result;
|
string_t result;
|
||||||
serializer s(detail::output_adapter_factory<char>::create(result), indent_char);
|
serializer s(detail::output_adapter<char>(result), indent_char);
|
||||||
|
|
||||||
if (indent >= 0)
|
if (indent >= 0)
|
||||||
{
|
{
|
||||||
|
@ -12783,7 +12792,7 @@ class basic_json
|
||||||
o.width(0);
|
o.width(0);
|
||||||
|
|
||||||
// do the actual serialization
|
// do the actual serialization
|
||||||
serializer s(detail::output_adapter_factory<char>::create(o), o.fill());
|
serializer s(detail::output_adapter<char>(o), o.fill());
|
||||||
s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
|
s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
@ -13162,11 +13171,15 @@ class basic_json
|
||||||
static std::vector<uint8_t> to_cbor(const basic_json& j)
|
static std::vector<uint8_t> to_cbor(const basic_json& j)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> result;
|
std::vector<uint8_t> result;
|
||||||
binary_writer bw(detail::output_adapter_factory<uint8_t>::create(result));
|
to_cbor(j, result);
|
||||||
bw.write_cbor(j);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)
|
||||||
|
{
|
||||||
|
binary_writer(o).write_cbor(j);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a MessagePack serialization of a given JSON value
|
@brief create a MessagePack serialization of a given JSON value
|
||||||
|
|
||||||
|
@ -13244,11 +13257,20 @@ class basic_json
|
||||||
static std::vector<uint8_t> to_msgpack(const basic_json& j)
|
static std::vector<uint8_t> to_msgpack(const basic_json& j)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> result;
|
std::vector<uint8_t> result;
|
||||||
binary_writer bw(detail::output_adapter_factory<uint8_t>::create(result));
|
to_msgpack(j, result);
|
||||||
bw.write_msgpack(j);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)
|
||||||
|
{
|
||||||
|
binary_writer(o).write_msgpack(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_msgpack(const basic_json& j, std::vector<uint8_t>& result)
|
||||||
|
{
|
||||||
|
binary_writer((detail::output_adapter<uint8_t>(result))).write_msgpack(j);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a JSON value from a byte vector in CBOR format
|
@brief create a JSON value from a byte vector in CBOR format
|
||||||
|
|
||||||
|
@ -13343,6 +13365,11 @@ class basic_json
|
||||||
return br.parse_cbor();
|
return br.parse_cbor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static basic_json from_cbor(detail::input_adapter i)
|
||||||
|
{
|
||||||
|
return binary_reader(i).parse_cbor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a JSON value from a byte vector in MessagePack format
|
@brief create a JSON value from a byte vector in MessagePack format
|
||||||
|
@ -13418,6 +13445,11 @@ class basic_json
|
||||||
return br.parse_msgpack();
|
return br.parse_msgpack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static basic_json from_msgpack(detail::input_adapter i)
|
||||||
|
{
|
||||||
|
return binary_reader(i).parse_msgpack();
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
|
@ -1519,16 +1519,60 @@ TEST_CASE("CBOR roundtrips", "[hide]")
|
||||||
std::ifstream f_json(filename);
|
std::ifstream f_json(filename);
|
||||||
json j1 = json::parse(f_json);
|
json j1 = json::parse(f_json);
|
||||||
|
|
||||||
// parse CBOR file
|
SECTION("std::vector<uint8_t>")
|
||||||
std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
|
{
|
||||||
std::vector<uint8_t> packed(
|
// parse CBOR file
|
||||||
(std::istreambuf_iterator<char>(f_cbor)),
|
std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
|
||||||
std::istreambuf_iterator<char>());
|
std::vector<uint8_t> packed(
|
||||||
json j2;
|
(std::istreambuf_iterator<char>(f_cbor)),
|
||||||
CHECK_NOTHROW(j2 = json::from_cbor(packed));
|
std::istreambuf_iterator<char>());
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_cbor(packed));
|
||||||
|
|
||||||
// compare parsed JSON values
|
// compare parsed JSON values
|
||||||
CHECK(j1 == j2);
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("std::ifstream")
|
||||||
|
{
|
||||||
|
// parse CBOR file
|
||||||
|
std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_cbor(f_cbor));
|
||||||
|
|
||||||
|
// compare parsed JSON values
|
||||||
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("uint8_t* and size")
|
||||||
|
{
|
||||||
|
// parse CBOR file
|
||||||
|
std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
|
||||||
|
std::vector<uint8_t> packed(
|
||||||
|
(std::istreambuf_iterator<char>(f_cbor)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()}));
|
||||||
|
|
||||||
|
// compare parsed JSON values
|
||||||
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("output to output adapters")
|
||||||
|
{
|
||||||
|
// parse CBOR file
|
||||||
|
std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
|
||||||
|
std::vector<uint8_t> packed(
|
||||||
|
(std::istreambuf_iterator<char>(f_cbor)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
SECTION("std::vector<uint8_t>")
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> vec;
|
||||||
|
json::to_cbor(j1, vec);
|
||||||
|
CHECK(vec == packed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ void check_escaped(const char* original, const char* escaped, const bool ensure_
|
||||||
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
|
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
json::serializer s(nlohmann::detail::output_adapter_factory<char>::create(ss), ' ');
|
json::serializer s(nlohmann::detail::output_adapter<char>(ss), ' ');
|
||||||
s.dump_escaped(original, ensure_ascii);
|
s.dump_escaped(original, ensure_ascii);
|
||||||
CHECK(ss.str() == escaped);
|
CHECK(ss.str() == escaped);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1292,15 +1292,60 @@ TEST_CASE("MessagePack roundtrips", "[hide]")
|
||||||
std::ifstream f_json(filename);
|
std::ifstream f_json(filename);
|
||||||
json j1 = json::parse(f_json);
|
json j1 = json::parse(f_json);
|
||||||
|
|
||||||
// parse MessagePack file
|
SECTION("std::vector<uint8_t>")
|
||||||
std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
|
{
|
||||||
std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_msgpack)),
|
// parse MessagePack file
|
||||||
std::istreambuf_iterator<char>());
|
std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
|
||||||
json j2;
|
std::vector<uint8_t> packed(
|
||||||
CHECK_NOTHROW(j2 = json::from_msgpack(packed));
|
(std::istreambuf_iterator<char>(f_msgpack)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_msgpack(packed));
|
||||||
|
|
||||||
// compare parsed JSON values
|
// compare parsed JSON values
|
||||||
CHECK(j1 == j2);
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("std::ifstream")
|
||||||
|
{
|
||||||
|
// parse MessagePack file
|
||||||
|
std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_msgpack(f_msgpack));
|
||||||
|
|
||||||
|
// compare parsed JSON values
|
||||||
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("uint8_t* and size")
|
||||||
|
{
|
||||||
|
// parse MessagePack file
|
||||||
|
std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
|
||||||
|
std::vector<uint8_t> packed(
|
||||||
|
(std::istreambuf_iterator<char>(f_msgpack)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
json j2;
|
||||||
|
CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()}));
|
||||||
|
|
||||||
|
// compare parsed JSON values
|
||||||
|
CHECK(j1 == j2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("output to output adapters")
|
||||||
|
{
|
||||||
|
// parse MessagePack file
|
||||||
|
std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
|
||||||
|
std::vector<uint8_t> packed(
|
||||||
|
(std::istreambuf_iterator<char>(f_msgpack)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
SECTION("std::vector<uint8_t>")
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> vec;
|
||||||
|
json::to_msgpack(j1, vec);
|
||||||
|
CHECK(vec == packed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue