mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-05-29 23:42:40 +02:00
Merge pull request #461 from redboltz/add_unpack_visitor_api
Added a visitor version of unpack API,
This commit is contained in:
commit
d15d9220ff
@ -44,7 +44,7 @@ public:
|
|||||||
m_pac.buffer_consumed(count);
|
m_pac.buffer_consumed(count);
|
||||||
|
|
||||||
msgpack::object_handle oh;
|
msgpack::object_handle oh;
|
||||||
while (m_pac.next(&oh)) {
|
while (m_pac.next(oh)) {
|
||||||
msgpack::object msg = oh.get();
|
msgpack::object msg = oh.get();
|
||||||
unique_zone& life = oh.zone();
|
unique_zone& life = oh.zone();
|
||||||
process_message(msg, life);
|
process_message(msg, life);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -76,17 +76,24 @@ using v1::detail::value;
|
|||||||
|
|
||||||
using v1::detail::load;
|
using v1::detail::load;
|
||||||
|
|
||||||
using v1::detail::context;
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
|
||||||
using v1::unpacked;
|
using v1::unpacked;
|
||||||
|
|
||||||
using v1::unpacker;
|
/// Unpacking class for a stream deserialization.
|
||||||
|
class unpacker;
|
||||||
|
|
||||||
using v1::unpack_return;
|
template <typename unpack_visitor, typename referenced_buffer_hook>
|
||||||
|
class basic_unpacker;
|
||||||
|
|
||||||
|
typedef enum unpack_return {
|
||||||
|
UNPACK_SUCCESS = v1::UNPACK_SUCCESS,
|
||||||
|
UNPACK_EXTRA_BYTES = v1::UNPACK_EXTRA_BYTES,
|
||||||
|
UNPACK_CONTINUE = v1::UNPACK_CONTINUE,
|
||||||
|
UNPACK_PARSE_ERROR = v1::UNPACK_PARSE_ERROR,
|
||||||
|
UNPACK_STOP_VISITOR = -2
|
||||||
|
} unpack_return;
|
||||||
|
|
||||||
/// Unpack msgpack::object from a buffer.
|
/// Unpack msgpack::object from a buffer.
|
||||||
/**
|
/**
|
||||||
@ -293,9 +300,42 @@ msgpack::object unpack(
|
|||||||
const char* data, std::size_t len,
|
const char* data, std::size_t len,
|
||||||
unpack_reference_func f = nullptr, void* user_data = nullptr, unpack_limit const& limit = unpack_limit());
|
unpack_reference_func f = nullptr, void* user_data = nullptr, unpack_limit const& limit = unpack_limit());
|
||||||
|
|
||||||
|
/// Unpack msgpack formatted data via a visitor
|
||||||
|
/**
|
||||||
|
* @param data The pointer to the buffer.
|
||||||
|
* @param len The length of the buffer.
|
||||||
|
* @param off The offset position of the buffer. It is read and overwritten.
|
||||||
|
* @param v The visitor that satisfies visitor concept. https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor#visitor-concept
|
||||||
|
*
|
||||||
|
* @return if unpacking process finishs without error then return true, otherwise return false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename Visitor>
|
||||||
|
bool parse(const char* data, size_t len, size_t& off, Visitor& v);
|
||||||
|
|
||||||
|
/// Unpack msgpack formatted data via a visitor
|
||||||
|
/**
|
||||||
|
* @param data The pointer to the buffer.
|
||||||
|
* @param len The length of the buffer.
|
||||||
|
* @param v The visitor that satisfies visitor concept. https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor#visitor-concept
|
||||||
|
*
|
||||||
|
* @return if unpacking process finishs without error then return true, otherwise return false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename Visitor>
|
||||||
|
bool parse(const char* data, size_t len, Visitor& v);
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
using v1::detail::unpack_imp;
|
unpack_return
|
||||||
|
unpack_imp(const char* data, std::size_t len, std::size_t& off,
|
||||||
|
msgpack::zone& result_zone, msgpack::object& result, bool& referenced,
|
||||||
|
unpack_reference_func f, void* user_data,
|
||||||
|
unpack_limit const& limit);
|
||||||
|
|
||||||
|
template <typename UnpackVisitor>
|
||||||
|
unpack_return
|
||||||
|
parse_imp(const char* data, size_t len, size_t& off, UnpackVisitor& v);
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ LIST (APPEND check_PROGRAMS
|
|||||||
streaming_c.cpp
|
streaming_c.cpp
|
||||||
user_class.cpp
|
user_class.cpp
|
||||||
version.cpp
|
version.cpp
|
||||||
|
visitor.cpp
|
||||||
zone.cpp
|
zone.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ check_PROGRAMS = \
|
|||||||
streaming_c \
|
streaming_c \
|
||||||
user_class \
|
user_class \
|
||||||
version \
|
version \
|
||||||
|
visitor \
|
||||||
zone
|
zone
|
||||||
|
|
||||||
check_PROGRAMS += \
|
check_PROGRAMS += \
|
||||||
@ -74,6 +75,7 @@ streaming_SOURCES = streaming.cpp
|
|||||||
streaming_c_SOURCES = streaming_c.cpp
|
streaming_c_SOURCES = streaming_c.cpp
|
||||||
user_class_SOURCES = user_class.cpp
|
user_class_SOURCES = user_class.cpp
|
||||||
version_SOURCES = version.cpp
|
version_SOURCES = version.cpp
|
||||||
|
visitor_SOURCES = visitor.cpp
|
||||||
zone_SOURCES = zone.cpp
|
zone_SOURCES = zone.cpp
|
||||||
|
|
||||||
iterator_cpp11_SOURCES = iterator_cpp11.cpp
|
iterator_cpp11_SOURCES = iterator_cpp11.cpp
|
||||||
|
@ -27,11 +27,11 @@ TEST(cases, format)
|
|||||||
feed_file(pac_compact, "cases_compact.mpac");
|
feed_file(pac_compact, "cases_compact.mpac");
|
||||||
|
|
||||||
msgpack::object_handle oh;
|
msgpack::object_handle oh;
|
||||||
while(pac.next(&oh)) {
|
while(pac.next(oh)) {
|
||||||
msgpack::object_handle oh_compact;
|
msgpack::object_handle oh_compact;
|
||||||
EXPECT_TRUE( pac_compact.next(&oh_compact) );
|
EXPECT_TRUE( pac_compact.next(oh_compact) );
|
||||||
EXPECT_EQ(oh_compact.get(), oh.get());
|
EXPECT_EQ(oh_compact.get(), oh.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_FALSE( pac_compact.next(&oh) );
|
EXPECT_FALSE( pac_compact.next(oh) );
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,9 @@ TEST(streaming, basic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// obsolete
|
||||||
|
#if MSGPACK_DEFAULT_API_VERSION == 1
|
||||||
|
|
||||||
TEST(streaming, basic_pointer)
|
TEST(streaming, basic_pointer)
|
||||||
{
|
{
|
||||||
msgpack::sbuffer buffer;
|
msgpack::sbuffer buffer;
|
||||||
@ -94,6 +97,8 @@ TEST(streaming, basic_pointer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // MSGPACK_DEFAULT_API_VERSION == 1
|
||||||
|
|
||||||
#if !defined(MSGPACK_USE_CPP03)
|
#if !defined(MSGPACK_USE_CPP03)
|
||||||
|
|
||||||
TEST(streaming, move)
|
TEST(streaming, move)
|
||||||
@ -207,6 +212,8 @@ TEST(streaming, event)
|
|||||||
handler.on_read();
|
handler.on_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// obsolete
|
||||||
|
#if MSGPACK_DEFAULT_API_VERSION == 1
|
||||||
|
|
||||||
// backward compatibility
|
// backward compatibility
|
||||||
TEST(streaming, basic_compat)
|
TEST(streaming, basic_compat)
|
||||||
@ -314,3 +321,5 @@ TEST(streaming, event_compat)
|
|||||||
handler.expect = 3;
|
handler.expect = 3;
|
||||||
handler.on_read();
|
handler.on_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !defined(MSGPACK_USE_CPP03)
|
||||||
|
141
test/visitor.cpp
Normal file
141
test/visitor.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <msgpack.hpp>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
// To avoid link error
|
||||||
|
TEST(visitor, dummy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MSGPACK_DEFAULT_API_VERSION >= 2
|
||||||
|
|
||||||
|
struct json_like_visitor : msgpack::v2::null_visitor {
|
||||||
|
json_like_visitor(std::string& s):m_s(s) {}
|
||||||
|
|
||||||
|
bool visit_nil() {
|
||||||
|
m_s += "null";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool visit_boolean(bool v) {
|
||||||
|
if (v) m_s += "true";
|
||||||
|
else m_s += "false";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool visit_positive_integer(uint64_t v) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << v;
|
||||||
|
m_s += ss.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool visit_negative_integer(int64_t v) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << v;
|
||||||
|
m_s += ss.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool visit_str(const char* v, uint32_t size) {
|
||||||
|
// I omit escape process.
|
||||||
|
m_s += '"' + std::string(v, size) + '"';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool start_array(uint32_t /*num_elements*/) {
|
||||||
|
m_s += "[";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool end_array_item() {
|
||||||
|
m_s += ",";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool end_array() {
|
||||||
|
m_s.erase(m_s.size() - 1, 1); // remove the last ','
|
||||||
|
m_s += "]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool start_map(uint32_t /*num_kv_pairs*/) {
|
||||||
|
m_s += "{";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool end_map_key() {
|
||||||
|
m_s += ":";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool end_map_value() {
|
||||||
|
m_s += ",";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool end_map() {
|
||||||
|
m_s.erase(m_s.size() - 1, 1); // remove the last ','
|
||||||
|
m_s += "}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void parse_error(size_t /*parsed_offset*/, size_t /*error_offset*/) {
|
||||||
|
EXPECT_TRUE(false);
|
||||||
|
}
|
||||||
|
void insufficient_bytes(size_t /*parsed_offset*/, size_t /*error_offset*/) {
|
||||||
|
EXPECT_TRUE(false);
|
||||||
|
}
|
||||||
|
std::string& m_s;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(visitor, json_like)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
msgpack::packer<std::stringstream> p(ss);
|
||||||
|
p.pack_map(1);
|
||||||
|
p.pack("key");
|
||||||
|
p.pack_array(3);
|
||||||
|
p.pack(42);
|
||||||
|
p.pack_nil();
|
||||||
|
p.pack(true);
|
||||||
|
|
||||||
|
std::string json_like;
|
||||||
|
json_like_visitor v(json_like);
|
||||||
|
std::size_t off = 0;
|
||||||
|
bool ret = msgpack::v2::parse(ss.str().data(), ss.str().size(), off, v);
|
||||||
|
EXPECT_TRUE(ret);
|
||||||
|
EXPECT_EQ("{\"key\":[42,null,true]}", json_like);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parse_error_check_visitor : msgpack::v2::null_visitor {
|
||||||
|
parse_error_check_visitor(bool& called):m_called(called) {}
|
||||||
|
void parse_error(size_t parsed_offset, size_t error_offset) {
|
||||||
|
EXPECT_EQ(1, parsed_offset);
|
||||||
|
EXPECT_EQ(2, error_offset);
|
||||||
|
m_called = true;
|
||||||
|
}
|
||||||
|
bool& m_called;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(visitor, parse_error)
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
parse_error_check_visitor v(called);
|
||||||
|
std::size_t off = 0;
|
||||||
|
char const data[] = { static_cast<char>(0x93u), 0x01u, static_cast<char>(0xc1u), 0x03u };
|
||||||
|
bool ret = msgpack::v2::parse(data, sizeof(data), off, v);
|
||||||
|
EXPECT_FALSE(ret);
|
||||||
|
EXPECT_TRUE(called);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct insuf_bytes_check_visitor : msgpack::v2::null_visitor {
|
||||||
|
insuf_bytes_check_visitor(bool& called):m_called(called) {}
|
||||||
|
void insufficient_bytes(size_t parsed_offset, size_t error_offset) {
|
||||||
|
EXPECT_EQ(2, parsed_offset);
|
||||||
|
EXPECT_EQ(3, error_offset);
|
||||||
|
m_called = true;
|
||||||
|
}
|
||||||
|
bool& m_called;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(visitor, insuf_bytes)
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
insuf_bytes_check_visitor v(called);
|
||||||
|
std::size_t off = 0;
|
||||||
|
char const data[] = { static_cast<char>(0x93u), 0x01u, 0x01u };
|
||||||
|
bool ret = msgpack::v2::parse(data, sizeof(data), off, v);
|
||||||
|
EXPECT_FALSE(ret);
|
||||||
|
EXPECT_TRUE(called);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MSGPACK_DEFAULT_API_VERSION >= 1
|
Loading…
x
Reference in New Issue
Block a user