Backends¶
All classes in this section satisfy concepts::backend
unless otherwise specified
JSON¶
-
class nloh¶
Provides json support via nlohammn/json
Supported types
Since nlohmann/json already has its own mechanism for parsing user-defined types, cronch leverages that first before falling back to its own metadata. If a type is not known to cronch and there is no nlohmann/json support for it then it will cause a compile error, unless it satisfies
concepts::iterable
, in which case it will be iterated over with the nlohmann::json instance being treated as an array.Supported formats
This backend supports any json supported by nlohmann/json, in addition to any binary formats it supports (currently cbor, msgpack, bson, and ubjson). Support for the binary formats is done via the
nloh::nloh()
overload which takes anlohmann::json
(allowing stuff such as nlohmann::json::from_bson to be passed) and theserialize()
overload which takes aBackend::document_type&
, allowing the caller full access to the underlyingnlohamnn::json
.Constructors
-
class boost¶
Provides json support via Boost.JSON
It is similar to the nlohmann backend, but due Boost.JSON’s lack of support for user-defined types, it adds its own system for conversion of them.
Supported types
All of Boost.JSON’s native types (object, array, string, etc). For additional type support, the
converter
struct is provided-
template<typename T>
class converter¶ Provides a customisation point for user-defined type support. Specialise it to add support. Specialisations are provided for the following out of the box:
std::string
anything satisfying std::intergral
Example
#include <cronch/json/boost.hpp> struct my_value_type { int i; }; template<> struct cronch::json::boost::converter<my_value_type> { void to_json(::boost::json::value& doc, const my_value_type& v) { doc.emplace_int64() = v.i; } void from_json(const ::boost::json::value& doc, my_value_type& v) { v.i = doc.as_int64(); } };
-
template<typename T>
XML¶
-
class pugi¶
Provides xml support via pugixml
The default version uses a node-per-value format. With the name of each node being either the name of the type (if from a type without members metadata or the top level node) or the name of the member it references.
Supported types
pugixml does not provide any way of parsing user defined types automatically. Instead it uses purely const char* for its values. Therefore, in order to successfully wrap pugi, cronch uses boost::lexical_cast<std::string>() to serialize types and boost::lexical_cast<T>() to deserialize them. See the docs on lexical cast for more information.
Types that are neither supported by lexical cast or have members known to cronch will cause a compile error, unless the type is
concepts::iterable
, in which case it must have at least a name known by cronch (either a member name or type name).XML structure
The output (and expected input) xml is of the form:
<typename>{inner}</typename>
wheretypename
is the name of the type passed topugi::serialize_to
and{inner}
is the result of serializing the inner members of that type. It will be one of the following (uses first matching, top to bottom):Satisfied concepts
Output
<member name>{inner}</member name>
for each memberostreamable
Result of boost::lexical_cast<std::string>(v) where
v
is the value<0..n>{inner}</0..n>
for each element 0 to n where n is the size of the iterable - 1Example
struct mytype { int i; std::vector<std::string> elements; }; const auto myvalue = mytype{ .i = 2, .elements = { "Hello", "World" } };
Here
myvalue
would be formatted as:<mytype> <i>2</i> <elements> <0>Hello</0> <1>World</1> </elements> </mytype>
Constructors
Building your own¶
Making your own backend is mostly quite simple. Define a type which satisfies concepts::backend
and use it. Done.
A very basic backend, which simply uses boost::lexical_cast to convert types, is shown below:
#include <cronch/deserialize.hpp>
#include <cronch/concepts.hpp>
#include <cronch/metatypes.hpp> // Provides meta::nameof<int>() support i.e serializable<int> is satisfied
#include <boost/lexical_cast.hpp>
#include <iostream>
class plain_backend {
public:
using document_type = std::string;
explicit plain_backend(std::string doc) : document_{std::move(doc)} {}
static void serialize_to(document_type& doc, const auto& v) {
doc += boost::lexical_cast<std::string>(v);
}
template<typename V>
void deserialize_to(V& v) const {
v = boost::lexical_cast<std::decay_t<V>>(document_);
}
static auto to_string(const document_type& doc) -> std::string {
return doc;
}
private:
std::string document_;
};
static_assert(cronch::concepts::backend<plain_backend>, "must be a backend");
int main(int argc, char** argv) {
if (argc != 2) {
std::cerr << "Invalid number of arguments, requires 1\n";
return EXIT_FAILURE;
}
const auto v = cronch::deserialize<int>(plain_backend{argv[1]});
std::cout << "You passed an int: " << v << '\n';
}