0

I am looking for a sample how to pack ext types with msgpack in C++ as I am not sure about how to do this.

The only information I found is located in this section https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_packer#pack-manually.

Assumed I want to pack an object of type Foo as a msgpack ext type with an adaptor class template. How to use pack_ext and pack_ext_body? Do I have to create a "sub packer" within the template, pack my Foo data manually and then pass size of the binary data and the data itself to pack_extand pack_ext_body? It would be create if some C++ expert could give me a minimal example.

MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
    namespace adaptor {
        template<>
        struct pack<Foo> {
            template <typename Stream>
            packer<Stream>& operator()(msgpack::packer<Stream>& o, Foo const& v) const {
                // how to use ?
                o.pack_ext(size_t l, int8_t type);
                o.pack_ext_body(const char* b, size_t l);
            }
       }
 }

}

Thanks in advance!

Robert_Jordan
  • 256
  • 4
  • 13

2 Answers2

0

I got it to work with my "sub packer" idea. I do not know if it is a good and elegant solution but at least it is working:

MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
    namespace adaptor {
        template<>
        struct pack<Foo> {
            template <typename Stream>
            packer<Stream>& operator()(msgpack::packer<Stream>& o, Foo const& v) const {
                msgpack::sbuffer sbuf;
                msgpack::packer<msgpack::sbuffer> sub_packer(sbuf);

                sub_packer.pack_map(2);

                sub_packer.pack("name");
                sub_packer.pack(v.name);

                sub_packer.pack("bar");
                sub_packer.pack(v.bar);

                // get binary data from sub_packer's sbuffer
                size_t l = sbuf.size();
                const char* b = sbuf.data();

                // pass ext type and binary data to originally packer
                o.pack_ext(l, 1);
                o.pack_ext_body(b, l);

                return o;
            }
        }
    }
}
Robert_Jordan
  • 256
  • 4
  • 13
0

You can use msgpack::type::ext or msgpack::type::ext_ref.

They are defined at https://github.com/msgpack/msgpack-c/blob/master/include/msgpack/v1/adaptor/ext.hpp

Here is an example for msgpack::type::ext:

#include <sstream>
#include <cassert>

#include <msgpack.hpp>

int main() {
    std::string val = "ABC";
    msgpack::type::ext e1(42, val.data(), val.size());

    assert(e1.type() == 42);
    assert(e1.size() == 3);
    assert(e1.data()[0] == 'A');
    assert(e1.data()[1] == 'B');
    assert(e1.data()[2] == 'C');

    std::stringstream ss;
    msgpack::pack(ss, e1);

    auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
    auto e2 = oh.get().as<msgpack::type::ext>();
    assert(e1 == e2);
}

Live demo: https://wandbox.org/permlink/ESmreWNBqDdXbKSf

You can also use msgpack::type::ext_ref. It can avoid copy operation but you need to keep the original buffer, in this case val and oh.

#include <sstream>
#include <cassert>

#include <msgpack.hpp>

int main() {
    std::string val = "\x2a"; // type 42
    val += "ABC";
    msgpack::type::ext_ref e1(val.data(), val.size());

    assert(e1.type() == 42);
    assert(e1.size() == 3);
    assert(e1.data()[0] == 'A');
    assert(e1.data()[1] == 'B');
    assert(e1.data()[2] == 'C');

    std::stringstream ss;
    msgpack::pack(ss, e1);

    auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
    auto e2 = oh.get().as<msgpack::type::ext_ref>();
    assert(e1 == e2);
}

Live demo: https://wandbox.org/permlink/uYr5MFjLJqPHQgj6

Takatoshi Kondo
  • 3,111
  • 17
  • 36