msgpack / msgpack-c

MessagePack implementation for C and C++ / msgpack.org[C/C++]
Other
3.03k stars 883 forks source link

Is it possible to only pack or unpack certain fields? #1019

Open dlandtaa opened 2 years ago

dlandtaa commented 2 years ago

Is there anyway to control which fields are packed or unpacked on a call by call basis?

Can I do something like this?

struct C
{
    int a;
    int b;
    int c;
    MSGPACK_DEFINE_MAP(a, b, c);
};

C c1;
c1.a = 1;
c1.b = 2;
c1.c = 3;

msgpack::sbuffer buff;
msgpack::packer<msgpack::sbuffer> packer(buff);

// only pack fields a and b
std::string fields1[] = { "a", "b" };
packer.pack(c1, fields1);

// only unpack field a
std::string fields2[] = { "a" };
msgpack::object_handle handle = msgpack::unpack(buff.data(), buff.size(), fields2);
msgpack::object obj = handle.get();
C c2;
obj.convert(c2);
redboltz commented 2 years ago

https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion msgpack-c has 3 concepts. They are pack/unpack/convert. (Creating object from T is not related in this context)

Can I do something like this?

pack

You can pack the only specific member variables but you need to call pack APIs directly.

See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_packer#pack-manually

unpack

You can't unpack only specific element using msgpack::unpack() function. You need to unpack all elements.

If you really want to only specific element from MessagePack formatted byte stream, then you can use visitor APIs. https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor It is like SAX api.

convert

If msgpack::object contains MAP like {"a":1,"b":2}, then you can get only "a":1 using direct access. But no key serach are provided. So first, convert to std::map<std::string, int> m and then get m["a"] is easy way.

sigasigasiga commented 11 months ago

Here's the way to somehow ignore certain fields:

struct C
{
    int a;
    int b;
    int c;
    MSGPACK_DEFINE_MAP(a, b, c);
};
msgpack::sbuffer buff;
msgpack::packer<msgpack::sbuffer> packer(buff);

struct C_fieldless
{
    int a;
    msgpack::object b, c; // the fields that are ignored
    MSGPACK_DEFINE_MAP(a, b, c);
};
msgpack::object_handle handle;
msgpack::unpack(handle, buff.data(), buff.size());
auto fieldless = handle.as<C_fieldsless>();