rapidyaml  0.16.0
parseandemitYAML,anddoitfast
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 
6 namespace c4 {
7 namespace yml {
8 
9 /** @addtogroup doc_serialization_using
10 
11 The top-level serialization functions are @ref NodeRef::save() / @ref
12 ConstNodeRef::load() to deserialize, and its tree equivalents @ref
13 Tree::save() / @ref Tree::load():
14 
15 @code{c++}
16 ryml::NodeRef node = ...;
17 // serialize
18 node.save(42);
19 CHECK(node.val() == "42");
20 // deserialize
21 int answer = 0;
22 node.load(&answer);
23 CHECK(answer == 42);
24 @endcode
25 or, if you prefer the tree API,
26 @code{c++}
27 ryml::Tree tree;
28 ryml::id_type node_id = ...;
29 // serialize
30 tree.save(node_id, 42);
31 CHECK(tree.val(node_id) == "42");
32 // deserialize
33 int answer = 0;
34 tree.load(node_id, &answer);
35 CHECK(answer == 42);
36 @endcode
37 
38 The functions for serializing keys are @ref NodeRef::save_key() to
39 serialize and @ref ConstNodeRef::load_key() to deserialize, and its
40 tree equivalents @ref Tree::save_key() and @ref Tree::load_key(). But
41 note that the Tree cannot handle container keys, so they must
42 serialized as a scalar.
43 
44 
45 <br>
46 <hr>
47 ## Setting styles while serializing
48 
49 When serializing scalars, it is advised to set explicit scalar styles when building
50 a tree for subsequently emitting. This is because YAML has constraints
51 on which styles can be used for a particular scalar.
52 
53 When the scalar is not marked with an explicit style, the ryml emitter
54 adheres to these constraints at run time by scanning each scalar to
55 choose a style for it. On the other hand, if the scalar is marked
56 with an explicit style, the emitter does not have to do the scan.
57 
58 So explicitly setting the style saves the emitter from having to scan
59 each scalar while emitting.
60 
61 @code{c++}
62 ryml::Tree tree = parse_in_arena("map:");
63 ryml::NodeRef map = tree["map"];
64 // serialize with explicit style
65 map["single quoted"].save("scalar", ryml::VAL_PLAIN);
66 map["single quoted"].save("scalar", ryml::VAL_SQUO);
67 map["double quoted"].save("scalar", ryml::VAL_DQUO);
68 map["literal"].save("scalar", ryml::VAL_LITERAL);
69 map["folded"].save("scalar", ryml::VAL_FOLDED);
70 CHECK(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 
82 The optional style parameter can and should be also used with all
83 the 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
92 met before attempting to read from the node, and it then checks the
93 success of the deserialization, triggering an error if anything
94 is wrong. To be clear, these are checks and not assertions, so they
95 are done regardless of build type.
96 
97 This results generally in safer user code, but comes at a slight cost.
98 You can avoid this cost, if you wish. First, `.load()` has a parameter
99 that turns the readability check into an assertion, but keeps the
100 deserialization check:
101 
102 @code{c++}
103 ryml::ConstNodeRef node = ...;
104 node.load(&answer, false); // disable readability check
105 @endcode
106 or, if you prefer the tree API
107 @code{c++}
108 ryml::Tree tree = ...;
109 ryml::id_type node_id = ...;
110 bool check_readable = false
111 tree.load(node_id, &answer, check_readable); // assumes the node is ok
112 @endcode
113 
114 And further, you can avoid exceptional flow in the code by using
115 instead @ref ConstNodeRef::deserialize() or @ref
116 Tree::deserialize(). These functions attempt to deserialize and return
117 a `[[nodiscard]]` boolean with the deserialization status:
118 
119 @code{c++}
120 ryml::ConstNodeRef node = ...;
121 if(... node is ok ...)
122  if(!node.deserialize(&answer))
123  ... // deserialization failed, react accordingly
124 @endcode
125 or, if you prefer the tree API
126 @code{c++}
127 ryml::Tree tree = ...;
128 ryml::id_type node_id = ...;
129 if(... node is ok ...)
130  if(!tree.deserialize(node_id, &answer))
131  ... // deserialization failed, react accordingly
132 @endcode
133 
134 Note 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 
160 That's it! ryml provides built-in serialization/deserialization
161 utilities for all fundamental data types, so you're good to go if
162 that's all you are using. However, read on if you want to implement
163 serialization with your own types.
164 
165 See now the basic sample @ref sample_serialize_basic() for a concrete
166 working example. And if you want to use serialization with your custom
167 user types, proceed to @ref doc_serialization_user_types.
168 */
169 
170 } // namespace yml
171 } // namespace c4
Node classes.