rapidyaml 0.15.2
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
doxy_serialization_using.hpp
Go to the documentation of this file.
1
2#include "c4/yml/tree.hpp"
3#include "c4/yml/node.hpp"
5
6namespace c4 {
7namespace yml {
8
9/** @addtogroup doc_serialization_using
10
11The top-level serialization functions are @ref NodeRef::save() / @ref
12ConstNodeRef::load() to deserialize, and its tree equivalents @ref
13Tree::save() / @ref Tree::load():
14
15@code{c++}
16ryml::NodeRef node = ...;
17// serialize
18node.save(42);
19CHECK(node.val() == "42");
20// deserialize
21int answer = 0;
22node.load(&answer);
23CHECK(answer == 42);
24@endcode
25or, if you prefer the tree API,
26@code{c++}
27ryml::Tree tree;
28ryml::id_type node_id = ...;
29// serialize
30tree.save(node_id, 42);
31CHECK(tree.val(node_id) == "42");
32// deserialize
33int answer = 0;
34tree.load(node_id, &answer);
35CHECK(answer == 42);
36@endcode
37
38The functions for serializing keys are @ref NodeRef::save_key() to
39serialize and @ref ConstNodeRef::load_key() to deserialize, and its
40tree equivalents @ref Tree::save_key() and @ref Tree::load_key(). But
41note that the Tree cannot handle container keys, so they must
42serialized as a scalar.
43
44
45<br>
46<hr>
47## Setting styles while serializing
48
49When serializing scalars, it is advised to set explicit scalar styles when building
50a tree for subsequently emitting. This is because YAML has constraints
51on which styles can be used for a particular scalar.
52
53When the scalar is not marked with an explicit style, the ryml emitter
54adheres to these constraints at run time by scanning each scalar to
55choose a style for it. On the other hand, if the scalar is marked
56with an explicit style, the emitter does not have to do the scan.
57
58So explicitly setting the style saves the emitter from having to scan
59each scalar while emitting.
60
61@code{c++}
62ryml::Tree tree = parse_in_arena("map:");
63ryml::NodeRef map = tree["map"];
64// serialize with explicit style
65map["single quoted"].save("scalar", ryml::VAL_PLAIN);
66map["single quoted"].save("scalar", ryml::VAL_SQUO);
67map["double quoted"].save("scalar", ryml::VAL_DQUO);
68map["literal"].save("scalar", ryml::VAL_LITERAL);
69map["folded"].save("scalar", ryml::VAL_FOLDED);
70CHECK(emitrs_yaml<std::string>(tree),
71 "map:\n"
72 "plain: scalar\n"
73 "single quoted: 'scalar'\n"
74 "double quoted: \"scalar\"\n"
75 "literal: |-\n
76 " \"scalar\"\n"
77 "folded: >-\n
78 " \"scalar\"\n"
79 );
80@endcode
81
82The optional style parameter can and should be also used with all
83the tree building functions (eg, @ref NodeRef::set_val(), etc).
84
85
86<br>
87<hr>
88
89## Checks: .load() vs .deserialize()
90
91`.load()` does a lot of hand-holding to ensure the preconditions are
92met before attempting to read from the node, and it then checks the
93success of the deserialization, triggering an error if anything
94is wrong. To be clear, these are checks and not assertions, so they
95are done regardless of build type.
96
97This results generally in safer user code, but comes at a slight cost.
98You can avoid this cost, if you wish. First, `.load()` has a parameter
99that turns the readability check into an assertion, but keeps the
100deserialization check:
101
102@code{c++}
103ryml::ConstNodeRef node = ...;
104node.load(&answer, false); // disable readability check
105@endcode
106or, if you prefer the tree API
107@code{c++}
108ryml::Tree tree = ...;
109ryml::id_type node_id = ...;
110bool check_readable = false
111tree.load(node_id, &answer, check_readable); // assumes the node is ok
112@endcode
113
114And further, you can avoid exceptional flow in the code by using
115instead @ref ConstNodeRef::deserialize() or @ref
116Tree::deserialize(). These functions attempt to deserialize and return
117a `[[nodiscard]]` boolean with the deserialization status:
118
119@code{c++}
120ryml::ConstNodeRef node = ...;
121if(... node is ok ...)
122 if(!node.deserialize(&answer))
123 ... // deserialization failed, react accordingly
124@endcode
125or, if you prefer the tree API
126@code{c++}
127ryml::Tree tree = ...;
128ryml::id_type node_id = ...;
129if(... node is ok ...)
130 if(!tree.deserialize(node_id, &answer))
131 ... // deserialization failed, react accordingly
132@endcode
133
134Note that `.deserialize()` still asserts readability.
135
136
137<br>
138<hr>
139
140## Examples
141
142 - See @ref sample_serialize_basic() and @ref doc_serialization_using
143 for an overview of how use serialization in ryml.
144 - See @ref sample_fundamental_types() for basic examples
145 of serialization of fundamental types.
146 - See @ref sample_empty_null_values() for different ways
147 to serialize and deserialize empty and null values/
148 - When serializing floating point values in C++ earlier than
149 17, be aware that there may be a truncation of the precision
150 with the default float/double implementations of @ref
151 doc_to_chars. To enforce a particular precision, use for
152 example @ref c4::fmt::real, or call directly @ref c4::ftoa() or
153 @ref c4::dtoa(), or any other method (remember that ryml only
154 stores the final string in the tree, so nothing prevents you from
155 creating it in whatever way is most suitable). See the relevant
156 sample: @ref sample_float_precision().
157 - You can also serialize and deserialize base64: see @ref
158 doc_base64 and @ref sample_base64
159
160That's it! ryml provides built-in serialization/deserialization
161utilities for all fundamental data types, so you're good to go if
162that's all you are using. However, read on if you want to implement
163serialization with your own types.
164
165See now the basic sample @ref sample_serialize_basic() for a concrete
166working example. And if you want to use serialization with your custom
167user types, proceed to @ref doc_serialization_user_types.
168*/
169
170} // namespace yml
171} // namespace c4
Node classes.