Упаковка типа ext в C++ с помощью Msgpack

Я ищу пример того, как упаковывать типы ext с помощью msgpack в C++, так как я не уверен, как это сделать.

Единственная информация, которую я нашел, находится в этом разделе https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_packer#pack-manually.

Предположим, я хочу упаковать объект типа Foo как тип расширения msgpack с шаблоном класса адаптера. Как использовать pack_ext и pack_ext_body? Должен ли я создать «подупаковщик» в шаблоне, вручную упаковать мои данные Foo, а затем передать размер двоичных данных и самих данных в pack_extи pack_ext_body? Это было бы создано, если бы какой-нибудь эксперт по C++ мог привести мне минимальный пример.

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);
            }
       }
 }

}

Заранее спасибо!


person Robert_Jordan    schedule 30.11.2017    source источник


Ответы (2)


Я заставил его работать с моей идеей «суб-упаковщика». Я не знаю, хорошее ли это и элегантное решение, но, по крайней мере, оно работает:

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;
            }
        }
    }
}
person Robert_Jordan    schedule 01.12.2017
comment
Пример из github: github.com/msgpack/msgpack-c/wiki/ - person andrzej1_1; 26.08.2020

Вы можете использовать msgpack::type::ext или msgpack::type::ext_ref.

Они определены на https://github.com/msgpack/msgpack-c/blob/master/include/msgpack/v1/adaptor/ext.hpp

Вот пример для 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);
}

Демонстрация в реальном времени: https://wandbox.org/permlink/ESmreWNBqDdXbKSf

Вы также можете использовать msgpack::type::ext_ref. Можно избежать операции копирования, но вам нужно сохранить исходный буфер, в данном случае val и 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);
}

Живая демонстрация: https://wandbox.org/permlink/uYr5MFjLJqPHQgj6

person Takatoshi Kondo    schedule 05.12.2017