Non-intrusive adapter macros
Currently there is only intrusive adapter macros (MSGPACK_DEFINE_ARRAY and MSGPACK_DEFINE_MAP), but no non-intrusive. A possible (incomplete) implementation is:
#define MY_DEFINE_MAP_EACH_PROC(r, data, elem) \
MSGPACK_PP_IF( \
MSGPACK_PP_IS_BEGIN_PARENS(elem), \
elem, \
(MSGPACK_PP_STRINGIZE(elem))(data.elem) \
)
#define MY_DEFINE_MAP_IMPL(var_name, ...) \
MSGPACK_PP_SEQ_TO_TUPLE( \
MSGPACK_PP_SEQ_FOR_EACH( \
MY_DEFINE_MAP_EACH_PROC, \
var_name, \
MSGPACK_PP_VARIADIC_TO_SEQ(__VA_ARGS__) \
) \
)
#define MSGPACK_ADD_CLASS(class_name, ...) \
namespace msgpack { \
/** @cond */ \
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) { \
/** @endcond */ \
namespace adaptor { \
template<> \
struct convert<class_name> { \
msgpack::object const& operator()(msgpack::object const& msgpack_o, class_name& msgpack_v) const { \
msgpack::type::make_define_map \
MY_DEFINE_MAP_IMPL(msgpack_v, __VA_ARGS__) \
.msgpack_unpack(msgpack_o); \
return msgpack_o; \
} \
}; \
template <> \
struct pack<class_name> { \
template <typename Stream> \
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& msgpack_pk, const class_name& msgpack_v) const { \
msgpack::type::make_define_map \
MY_DEFINE_MAP_IMPL(msgpack_v, __VA_ARGS__) \
.msgpack_pack(msgpack_pk); \
return msgpack_pk; \
} \
}; \
} \
/** @cond */ \
} \
/** @endcond */ \
}
MSGPACK_ADD_CLASS(your_class, a, b, c) expands to:
namespace msgpack {
inline namespace v3 {
namespace adaptor {
template<> struct convert<your_class> {
msgpack::object const& operator()(msgpack::object const& msgpack_o, your_class& msgpack_v) const {
msgpack::type::make_define_map ("a", msgpack_v.a, "b", msgpack_v.b, "c", msgpack_v.c ) .msgpack_unpack(msgpack_o); return msgpack_o;
}
};
template <> struct pack<your_class> {
template <typename Stream> msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& msgpack_pk, const your_class& msgpack_v) const {
msgpack::type::make_define_map ("a", msgpack_v.a, "b", msgpack_v.b, "c", msgpack_v.c ) .msgpack_pack(msgpack_pk); return msgpack_pk;
}
};
}
}
}
MSGPACK_NVP is not working with this implementation.
Interesting idea.
But non-intrusive use case is various.
Users might want to have any combination of as convert pack object object_with_zone. Some of them cannot be implemented. It depends on user type.
At least they should be separated. So far, intrusive macro is for causal users and non-intrusive one is for advanced users.
As you mentioned MSGPACK_NVP should work well with the macros.
So far, I have no plan to providing non-intrusive macros. But pull request that solves the all issues that I mentioned, we are open to review and merge it.
In my projects I use both MsgPack to serizalize/deserialize objects with MSGPACK_DEFINE_MAP and Cereal to/from JSON. Cereal supports non-intrusive serialization functions and I found it to be very practical:
- I can add serialization capability to classes that I do not own (coming from a library)
- I can encapsulate serialization functionality into a cpp
With MsgPack if I want a class to be serializable and add MSGPACK_DEFINE_MAP that means that I have to include MsgPack headers everywhere where the class is used, and MsgPack is not that lightweight.
msgpack-c C++ supports non-intrusive adaptor. See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor#non-intrusive-approach
Ok, indeed it is possible to write serialization functionality in a non-intrusive way, but as I see the whole purpose of MSGPACK_DEFINE_MAP is to generate this (non-trivial) boilerplate for me. From my point of view there should be a non-member MSGPACK_DEFINE_MAP to write the non-intrusive boilerplate as well. Of course I understand the technical difficulties associated with it.
When you write a pull request that contains the following functionalities and tests then I would review it.
These are non intrusive adaptor macros. The macro name is just idea. Separated macros are better because some of them are impossible to implement due to the target class restriction. Both ARRAY and MAP adaptor should be supported. User can choose ARRAY or MAP version (maybe exclusively) by the target class. User can also choose with operation is supported.
MSGPACK_ADAPTOR_ARRAY_CONVERT(...)
MSGPACK_ADAPTOR_ARRAY_AS(...)
MSGPACK_ADAPTOR_ARRAY_PACK(...)
MSGPACK_ADAPTOR_ARRAY_OBJECT(...)
MSGPACK_ADAPTOR_ARRAY_OBJECT_WITH_ZONE(...)
MSGPACK_ADAPTOR_MAP_CONVERT(...)
MSGPACK_ADAPTOR_MAP_AS(...)
MSGPACK_ADAPTOR_MAP_PACK(...)
MSGPACK_ADAPTOR_MAP_OBJECT(...)
MSGPACK_ADAPTOR_MAP_OBJECT_WITH_ZONE(...)