diff --git a/README.md b/README.md index 2b0ba02a..c763488c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Rapid YAML [![MIT Licensed](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/biojppm/rapidyaml/blob/master/LICENSE.txt) [![release](https://img.shields.io/github/v/release/biojppm/rapidyaml?color=g&include_prereleases&label=release%20&sort=semver)](https://github.com/biojppm/rapidyaml/releases) -[![Documentation Status](https://readthedocs.org/projects/rapidyaml/badge/?version=latest)](https://rapidyaml.readthedocs.io/en/latest/?badge=latest) +[![Documentation Status](https://readthedocs.org/projects/rapidyaml/badge/?version=latest)](https://rapidyaml.readthedocs.io/latest/?badge=latest) [![PyPI](https://img.shields.io/pypi/v/rapidyaml?color=g)](https://pypi.org/project/rapidyaml/) [![Gitter](https://badges.gitter.im/rapidyaml/community.svg)](https://gitter.im/rapidyaml/community) @@ -51,7 +51,7 @@ ryml is written in C++11, and compiles cleanly with: * Intel Compiler ryml's API documentation is [available at -ReadTheDocs](https://rapidyaml.readthedocs.io/en/latest/). +ReadTheDocs](https://rapidyaml.readthedocs.io/latest/). ryml is [extensively unit-tested in Linux, Windows and MacOS](https://github.com/biojppm/rapidyaml/actions). The tests cover @@ -239,7 +239,7 @@ level API for accessing and traversing the data tree. The following snippet is a very quick overview taken from quickstart sample ([see on -doxygen](https://rapidyaml.readthedocs.io/en/latest/group__doc__quickstart.html)/[see +doxygen](https://rapidyaml.readthedocs.io/latest/group__doc__quickstart.html)/[see on github](samples/quickstart.cpp). After cloning ryml (don't forget the `--recursive` flag for git), you can very easily build and run this executable using any of the build samples, eg the diff --git a/doc/Doxyfile b/doc/Doxyfile index 8cddb3f0..2348b229 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -957,6 +957,9 @@ INPUT = \ ../ext/c4core/src/c4/charconv.hpp \ ../ext/c4core/src/c4/format.hpp \ ../ext/c4core/src/c4/base64.hpp \ + ../ext/c4core/src/c4/std/string.hpp \ + ../ext/c4core/src/c4/std/string_view.hpp \ + ../ext/c4core/src/c4/std/vector.hpp \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -2495,6 +2498,8 @@ PREDEFINED = \ "C4_MUST_BE_TRIVIAL_COPY(cls)= " \ "C4_NO_INLINE= " \ "C4_NO_UBSAN_IOVRFLW= " \ + "C4_NODISCARD= " \ + "C4_NORETURN= " \ "C4_PURE= " \ "C4_REQUIRE_RW(ty)=ty " \ "C4_RESTRICT= " \ diff --git a/doc/doxy_main.md b/doc/doxy_main.md index 749ecf16..04afe2c0 100644 --- a/doc/doxy_main.md +++ b/doc/doxy_main.md @@ -10,25 +10,7 @@ * @ref doc_node_type * @ref doc_tree * @ref doc_node_classes - * For serialization/deserialization: - * See @ref sample_scalar_types for when the type is scalar (a leaf node in the YAML tree, containing a string representation): - * See examples on how to @ref sample_to_chars_scalar - * See examples on how to @ref sample_from_chars_scalar - * See the sample @ref sample::sample_user_scalar_types - * When serializing floating point values in C++ earlier than 17, - be aware that there may be a truncation of the precision with - the default to_chars implementation. To enforce a particular - precision, use for example @ref c4::fmt::real, or call - directly @ref c4::ftoa or @ref c4::dtoa, or any other method - (remember that ryml only stores the final string, so nothing - prevents you from creating it). See the relevant sample: @ref - sample::sample_float_precision. - * See @ref sample_container_types for when the type is a container (ie, a node which has children, which may themselves be containers). - * See the sample @ref sample::sample_user_container_types - * ryml does not use any STL containers internally, but it can be - used to serialize and deserialize these containers. See @ref - sample::sample_std_types for an example. See the header @ref - ryml_std.hpp and also the headers it includes. + * For serialization/deserialization, see @ref doc_serialization. * @ref doc_tag_utils - how to resolve tags * @ref doc_callbacks - how to set up error/allocation/deallocation callbacks either globally for the library, or for specific objects diff --git a/ext/c4core b/ext/c4core index 98f783e4..1cd92b7f 160000 --- a/ext/c4core +++ b/ext/c4core @@ -1 +1 @@ -Subproject commit 98f783e462daddfe8b12ea2741515315fb1c44af +Subproject commit 1cd92b7f3372e020eca5a1bbb57f5e7059eb8cdd diff --git a/samples/quickstart.cpp b/samples/quickstart.cpp index 6792e418..efcfa415 100644 --- a/samples/quickstart.cpp +++ b/samples/quickstart.cpp @@ -247,7 +247,7 @@ struct ScopedErrorHandlerExample : public ErrorHandlerExample ~ScopedErrorHandlerExample() { ryml::set_callbacks(defaults); check_effect(false); } }; -/** @} */ // sample_helpers +/** @} */ // doc_sample_helpers //----------------------------------------------------------------------------- @@ -2373,7 +2373,8 @@ void sample_tree_arena() those types that should be serialized as strings in leaf nodes), you just need to define the appropriate overloads of to_chars and from_chars for those types; see @ref sample_user_scalar_types for - an example on how to achieve this. */ + an example on how to achieve this, and see @ref doc_serialization + for more information on serialization. */ void sample_fundamental_types() { ryml::Tree tree; @@ -2437,7 +2438,8 @@ void sample_fundamental_types() //----------------------------------------------------------------------------- -/** Shows how to deal with empty/null values. See also @ref c4::yml::Tree::val_is_null */ +/** Shows how to deal with empty/null values. See also @ref + * c4::yml::Tree::val_is_null */ void sample_empty_null_values() { // reading empty/null values - see also sample_formatting() @@ -2600,8 +2602,10 @@ str_tilde: ~ //----------------------------------------------------------------------------- -/** ryml provides facilities for formatting (imported from c4core into - * the ryml namespace) - see @ref doc_format_utils +/** ryml provides facilities for formatting/deformatting (imported + * from c4core into the ryml namespace). See @ref doc_format_utils + * . These functions are very useful to serialize and deserialize + * scalar types; see @ref doc_serialization . */ void sample_formatting() { @@ -3233,13 +3237,94 @@ QmVsaWtlIGZvciB3YW50IG9mIHJhaW4sIHdoaWNoIEkgY291bGQgd2VsbCBiZXRlZW0gdGhlbSBmcm9t } +//----------------------------------------------------------------------------- +// Serialization info + +} // namespace sample // because we want the doxygen document above to show up in the proper place +/** @addtogroup doc_serialization + * + * ## Fundamental types + * + * ryml provides serialization/deserialization utilities for all + * fundamental data types in @ref doc_charconv . + * + * - See @ref sample::sample_fundamental_types() for basic examples + * of serialization of fundamental types. + * - See @ref sample::sample_empty_null_values() for different ways + * to serialize and deserialize empty and null values/ + * - When serializing floating point values in C++ earlier than + * 17, be aware that there may be a truncation of the precision + * with the default float/double implementations of @ref + * doc_to_chars. To enforce a particular precision, use for + * example @ref c4::fmt::real, or call directly @ref c4::ftoa() or + * @ref c4::dtoa(), or any other method (remember that ryml only + * stores the final string in the tree, so nothing prevents you from + * creating it in whatever way is most suitable). See the relevant + * sample: @ref sample::sample_float_precision(). + * - You can also serialize and deserialize base64: see @ref + * doc_base64 and @ref sample::sample_base64 + * + * To serialize/deserialize any non-fundamental type will require + * that you instruct ryml on how to achieve this. That will differ + * based on whether the type is scalar or container. + * + * + * ## User scalar types + * + * See @ref doc_sample_scalar_types for serializing user scalar types + * (ie leaf nodes in the YAML tree, containing a string + * representation): + * + * - See examples on how to @ref doc_sample_to_chars_scalar + * - See examples on how to @ref doc_sample_from_chars_scalar + * - See the sample @ref sample::sample_user_scalar_types + * - See the sample @ref sample::sample_formatting for examples + * of functions from @ref doc_format_utils that will be very + * helpful in implementing custom `to_chars()`/`from_chars()` + * functions. + * - See @ref doc_charconv for the implementations of + * `to_chars()`/`from_chars()` for the fundamental types. + * - See @ref doc_substr and @ref sample::sample_substr() for the + * many useful utilities in the substring class. + * + * + * ## User container types + * + * - See @ref doc_sample_container_types for when the type is a + * container (ie, a node which has children, which may themselves be + * containers). + * + * - See the sample @ref sample::sample_user_container_types + * + * - See the sample @ref sample::sample_std_types, and also... + * + * + * ## STL types + * + * ryml does not use any STL containers internally, but it can be + * used to serialize and deserialize these containers. See @ref + * sample::sample_std_types() for an example. See the header @ref + * ryml_std.hpp and also the headers it includes: + * + * - scalar types: + * - for `std::string`: @ref ext/c4core/src/c4/std/string.hpp + * - for `std::string_view`: @ref ext/c4core/src/c4/std/string_view.hpp + * - for `std::vector`: @ref ext/c4core/src/c4/std/vector.hpp + * - container types: + * - for `std::vector`: @ref src/c4/yml/std/vector.hpp + * - for `std::map`: @ref src/c4/yml/std/map.hpp + * + */ +namespace sample { // because we want the doxygen document above to show up in the proper place + + //----------------------------------------------------------------------------- // user scalar types: implemented in ryml through to_chars() + from_chars() /** @addtogroup doc_sample_helpers * @{ */ -/** @defgroup sample_scalar_types Serialize/deserialize scalar types +/** @defgroup doc_sample_scalar_types Serialize/deserialize scalar types * @{ */ template struct vec2 { T x, y; }; ///< example scalar type, serialized and deserialized @@ -3254,10 +3339,10 @@ template struct emit_only_vec2 { T x, y; }; ///< example scalar type, s template struct emit_only_vec3 { T x, y, z; }; ///< example scalar type, serialized only template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar type, serialized only -/** @defgroup sample_to_chars_scalar Define to_chars to write scalar types +/** @defgroup doc_sample_to_chars_scalar Define to_chars to write scalar types * * @brief To serialize user scalar types, implement the appropriate - * function to_chars (see also @ref doc_to_chars) + * function to_chars (see also @ref doc_to_chars): * * ```cpp * // any of these can be used: @@ -3265,6 +3350,8 @@ template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar t * size_t to_chars(substr buf, T v); // this also works, and is good when the type is small * ``` * + * See the sample @ref sample_user_scalar_types() for an example usage. + * * Your implementation of to_chars must format v to the given string * view + return the number of characters written into it. The view * size (buf.len) must be strictly respected. Return the number of @@ -3277,21 +3364,28 @@ template struct emit_only_vec4 { T x, y, z, w; }; ///< example scalar t * formatting facilities in @ref doc_format_utils and @ref doc_charconv; * refer to their documentation for further details. But this is not * mandatory, and anything can be used, provided that the implemented - * to_chars fulfills its contract, described above. + * `to_chars()` fulfills its contract, described above. * - * To harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl), - * it is important to overload these functions in the namespace of the type - * you're serializing (or in the c4::yml namespace). + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. - * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `to_chars()` implementation before any other headers that use + * functions from it. See the include order at the top of this source + * file. This constraint also applies to the conversion functions for + * your types; just like with the STL's headers, they should be + * included prior to ryml's headers. Lately, some effort was directed + * to provide forward declarations to alleviate this problem, but it + * may still occur. * + * @see string.hpp + * @see string_view.hpp * @{ */ template size_t to_chars(ryml::substr buf, vec2 v) { return ryml::format(buf, "({},{})", v.x, v.y); } @@ -3304,7 +3398,7 @@ template size_t to_chars(ryml::substr buf, emit_only_vec4 v) { retur /** @} */ -/** @defgroup sample_from_chars_scalar Define from_chars to read scalar types +/** @defgroup doc_sample_from_chars_scalar Define from_chars to read scalar types * * @brief To deserialize user scalar types, implement the * function `bool from_chars(csubstr buf, T *val)`; see @ref @@ -3322,18 +3416,23 @@ template size_t to_chars(ryml::substr buf, emit_only_vec4 v) { retur * mandatory, and anything can be used, provided that the implemented * from_chars fulfills its contract, described above. * - * To harness [C++'s ADL rules](http://en.cppreference.com/w/cpp/language/adl), - * it is important to overload these functions in the namespace of the type - * you're serializing (or in the c4::yml namespace). - * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `from_chars()` implementation before any other headers that use + * functions from it. See the include order at the top of this source + * file. This constraint also applies to the conversion functions for + * your types; just like with the STL's headers, they should be + * included prior to ryml's headers. Lately, some effort was directed + * to provide forward declarations to alleviate this problem, but it + * may still occur. * * @{ */ @@ -3344,15 +3443,15 @@ template bool from_chars(ryml::csubstr buf, vec4 *v) { size_t ret = template bool from_chars(ryml::csubstr buf, parse_only_vec2 *v) { size_t ret = ryml::unformat(buf, "({},{})", v->x, v->y); return ret != ryml::yml::npos; } template bool from_chars(ryml::csubstr buf, parse_only_vec3 *v) { size_t ret = ryml::unformat(buf, "({},{},{})", v->x, v->y, v->z); return ret != ryml::yml::npos; } template bool from_chars(ryml::csubstr buf, parse_only_vec4 *v) { size_t ret = ryml::unformat(buf, "({},{},{},{})", v->x, v->y, v->z, v->w); return ret != ryml::yml::npos; } -/** @} */ // sample_from_chars_scalar +/** @} */ // doc_sample_from_chars_scalar -/** @} */ // sample_scalar_types -/** @} */ // sample_helpers +/** @} */ // doc_sample_scalar_types +/** @} */ // doc_sample_helpers /** to add scalar types (ie leaf types converting to/from string), * define the functions above for those types. See @ref - * sample_scalar_types. */ + * doc_sample_scalar_types. */ void sample_user_scalar_types() { ryml::Tree t; @@ -3422,7 +3521,7 @@ v4: '(40,41,42,43)' /** @addtogroup doc_sample_helpers * @{ */ -/** @defgroup sample_container_types Serialize/deserialize container types +/** @defgroup doc_sample_container_types Serialize/deserialize container types * * To serialize/deserialize container types to a tree, implement the * appropriate functions: @@ -3432,14 +3531,26 @@ v4: '(40,41,42,43)' * bool read(ryml::ConstNodeRef const& n, T *seq); * ``` * - * Please take note of the following pitfall when using serialization - * functions: you have to include the header with the serialization - * before any other headers that use functions from it. see the - * include order at the top of this file. + * @warning Because of [C++'s ADL + * rules](http://en.cppreference.com/w/cpp/language/adl), **it is + * required to overload these functions in the namespace of the type** + * you're serializing (or in the c4 namespace, or in the c4::yml + * namespace). [Here's an example of an issue where failing to do this + * was causing problems in some + * platforms](https://github.com/biojppm/rapidyaml/issues/424) * - * This constraint also applies to the conversion functions for your - * types; just like with the STL's headers, they should be included - * prior to ryml's headers. + * @note Please take note of the following pitfall when using + * serialization functions: you may have to include the header with + * your `write()` or `read()` implementation before any other headers + * that use functions from it. See the include order at the top of + * this source file. This constraint also applies to the conversion + * functions for your types; just like with the STL's headers, they + * should be included prior to ryml's headers. Lately, some effort was + * directed to provide forward declarations to alleviate this problem, + * but it may still occur. + * + * @see sample::sample_container_types + * @see sample::sample_std_types * * @{ */ @@ -3528,13 +3639,15 @@ bool read(ryml::ConstNodeRef const& n, my_type *val) return true; } -/** @} */ // sample_container_types +/** @} */ // doc_sample_container_types /** @} */ // sample_helpers /** shows how to serialize/deserialize container types. - * @see sample_container_types */ + * @see doc_sample_container_types + * @see sample_std_types + * */ void sample_user_container_types() { my_type mt_in{ @@ -3591,17 +3704,11 @@ v4: '(40,41,42,43)' //----------------------------------------------------------------------------- -// -// Please take note of the following pitfall when using serialization -// functions: you have to include the header with the serialization -// before any other headers that use functions from it. see the -// include order at the top of this file. -// -// This constraint also applies to the conversion functions for your -// types; just like with the STL's headers, they should be included -// prior to ryml's headers. -/** demonstrates usage with the std implementations provided by ryml in the ryml_std.hpp header */ +/** demonstrates usage with the std implementations provided by ryml + in the ryml_std.hpp header + @see @ref doc_sample_container_types + @see also the STL section in @ref doc_serialization */ void sample_std_types() { std::string yml_std_string = R"(- v2: '(20,21)' @@ -4950,7 +5057,6 @@ C4_NORETURN void ErrorHandlerExample::s_error(const char* msg, size_t len, ryml: /** this is the where the callback implementation goes. Remember that it must not return. */ C4_NORETURN void ErrorHandlerExample::on_error(const char* msg, size_t len, ryml::Location loc) { - std::cout << "aqui foo!\n"; std::string full_msg = ryml::formatrs( "{}:{}:{} ({}B): ERROR: {}", loc.name, loc.line, loc.col, loc.offset, ryml::csubstr(msg, len)); diff --git a/src/c4/yml/common.hpp b/src/c4/yml/common.hpp index d7f9edba..d08281ea 100644 --- a/src/c4/yml/common.hpp +++ b/src/c4/yml/common.hpp @@ -75,6 +75,14 @@ * @see sample::sample_per_tree_allocator */ +/** @defgroup doc_serialization Serialization/deserialization + * + * Contains information on how to serialize and deserialize + * fundamental types, user scalar types, user container types and + * interop with std scalar/container types. + * + */ + /** @defgroup doc_tag_utils Tag utilities * @see sample::sample_tags */