rapidyaml  0.16.0
parseandemitYAML,anddoitfast
How to use (de)serialization

Shows basic use of the calls to serialize and deserialize. More...

Shows basic use of the calls to serialize and deserialize.

The top-level serialization functions are NodeRef::save() / ConstNodeRef::load() to deserialize, and its tree equivalents Tree::save() / Tree::load():

See also
sample_serialize_basic()
Serialization of user types to implement for user types
{c++}
ryml::NodeRef node = ...;
// serialize
node.save(42);
CHECK(node.val() == "42");
// deserialize
int answer = 0;
node.load(&answer);
CHECK(answer == 42);

or, if you prefer the tree API,

{c++}
ryml::id_type node_id = ...;
// serialize
tree.save(node_id, 42);
CHECK(tree.val(node_id) == "42");
// deserialize
int answer = 0;
tree.load(node_id, &answer);
CHECK(answer == 42);

The functions for serializing keys are NodeRef::save_key() to serialize and ConstNodeRef::load_key() to deserialize, and its tree equivalents Tree::save_key() and Tree::load_key(). But note that the Tree cannot handle container keys, so they must serialized as a scalar.



Setting styles while serializing

When serializing scalars, it is advised to set explicit scalar styles when building a tree for subsequently emitting. This is because YAML has constraints on which styles can be used for a particular scalar.

When the scalar is not marked with an explicit style, the ryml emitter adheres to these constraints at run time by scanning each scalar to choose a style for it. On the other hand, if the scalar is marked with an explicit style, the emitter does not have to do the scan.

So explicitly setting the style saves the emitter from having to scan each scalar while emitting.

{c++}
ryml::Tree tree = parse_in_arena("map:");
ryml::NodeRef map = tree["map"];
// serialize with explicit style
map["single quoted"].save("scalar", ryml::VAL_PLAIN);
map["single quoted"].save("scalar", ryml::VAL_SQUO);
map["double quoted"].save("scalar", ryml::VAL_DQUO);
map["literal"].save("scalar", ryml::VAL_LITERAL);
map["folded"].save("scalar", ryml::VAL_FOLDED);
CHECK(emitrs_yaml<std::string>(tree),
"map:\n"
"plain: scalar\n"
"single quoted: 'scalar'\n"
"double quoted: \"scalar\"\n"
"literal: |-\n
" \"scalar\"\n"
"folded: >-\n
" \"scalar\"\n"
);

The optional style parameter can and should be also used with all the tree building functions (eg, NodeRef::set_val(), etc).



Checks: .load() vs .deserialize()

.load() does a lot of hand-holding to ensure the preconditions are met before attempting to read from the node, and it then checks the success of the deserialization, triggering an error if anything is wrong. To be clear, these are checks and not assertions, so they are done regardless of build type.

This results generally in safer user code, but comes at a slight cost. You can avoid this cost, if you wish. First, .load() has a parameter that turns the readability check into an assertion, but keeps the deserialization check:

{c++}
ryml::ConstNodeRef node = ...;
node.load(&answer, false); // disable readability check

or, if you prefer the tree API

{c++}
ryml::Tree tree = ...;
ryml::id_type node_id = ...;
bool check_readable = false
tree.load(node_id, &answer, check_readable); // assumes the node is ok

And further, you can avoid exceptional flow in the code by using instead ConstNodeRef::deserialize() or Tree::deserialize(). These functions attempt to deserialize and return a [[nodiscard]] boolean with the deserialization status:

{c++}
ryml::ConstNodeRef node = ...;
if(... node is ok ...)
if(!node.deserialize(&answer))
... // deserialization failed, react accordingly

or, if you prefer the tree API

{c++}
ryml::Tree tree = ...;
ryml::id_type node_id = ...;
if(... node is ok ...)
if(!tree.deserialize(node_id, &answer))
... // deserialization failed, react accordingly

Note that .deserialize() still asserts readability.



Examples

That's it! ryml provides built-in serialization/deserialization utilities for all fundamental data types, so you're good to go if that's all you are using. However, read on if you want to implement serialization with your own types.

See now the basic sample sample_serialize_basic() for a concrete working example. And if you want to use serialization with your custom user types, proceed to Serialization of user types.