### Add API documentation

- [PR#423](https://github.com/biojppm/rapidyaml/pull/423): **add Doxygen-based API documentation, now hosted in [https://rapidyaml.readthedocs.io/](https://rapidyaml.readthedocs.io/)!**
- It uses the base doxygen docs, as I couldn't get doxyrest or breathe or exhale to produce anything meaningful using the doxygen groups already defined in the source code.


### Error handling

Fix major error handling problem reported in [#389](https://github.com/biojppm/rapidyaml/issues/389) ([PR#411](https://github.com/biojppm/rapidyaml/pull/411)):

  - The `NodeRef` and `ConstNodeRef` classes are now conditional noexcept using `RYML_NOEXCEPT`, which evaluates either to nothing when assertions are enabled, and to `noexcept` otherwise. The problem was that these classes had many methods explicitly marked `noexcept`, but were doing assertions which could throw exceptions, causing an abort instead of a throw whenever the assertion called an exception-throwing error callback.
  - This problem was compounded by assertions being enabled in every build type -- despite the intention to have them only in debug builds. There was a problem in the preprocessor code to enable assertions which led to assertions being enabled in release builds even when `RYML_USE_ASSERT` was defined to 0. Thanks to @jdrouhard for reporting this.
  - Although the code is and was extensively tested, the testing was addressing mostly the happy path. Tests were added to ensure that the error behavior is as intended.
  - Together with this changeset, a major revision was carried out of the asserting/checking status of each function in the node classes. In most cases, assertions were added to functions that were missing them. So **beware** - some user code that was invalid will now assert or error out. Also, assertions and checks are now directed as much as possible to the callbacks of the closest scope: ie, if a tree has custom callbacks, errors within the tree class should go through those callbacks.
  - Also, the intended assertion behavior is now in place: *no assertions in release builds*. **Beware** as well - user code which was relying on this will now silently succeed and return garbage in release builds. See the next points, which may help.
  - Added new methods to the `NodeRef`/`ConstNodeRef` classes:
    ```c++
    /** Distinguish between a valid seed vs a valid non-seed ref. */
    bool readable() const { return valid() && !is_seed(); }

    /** Get a child by name, with error checking; complexity is
     * O(num_children).
     *
     * Behaves as operator[](csubstr) const, but always raises an
     * error (even when RYML_USE_ASSERT is set to false) when the
     * returned node does not exist, or when this node is not
     * readable, or when it is not a map. This behaviour is similar to
     * std::vector::at(), but the error consists in calling the error
     * callback instead of directly raising an exception. */
    ConstNodeRef at(csubstr key) const;
    /** Likewise, but return a seed node when the key is not found */
    NodeRef at(csubstr key);

    /** Get a child by position, with error checking; complexity is
     * O(pos).
     *
     * Behaves as operator[](size_t) const, but always raises an error
     * (even when RYML_USE_ASSERT is set to false) when the returned
     * node does not exist, or when this node is not readable, or when
     * it is not a container. This behaviour is similar to
     * std::vector::at(), but the error consists in calling the error
     * callback instead of directly raising an exception. */
    ConstNodeRef at(size_t pos) const;
    /** Likewise, but return a seed node when pos is not found */
    NodeRef at(csubstr key);
    ```
  - The state for `NodeRef` was refined, and now there are three mutually exclusive states (and class predicates) for an object of this class:
    - `.invalid()` when the object was not initialized to any node
    - `.readable()` when the object points at an existing tree+node
    - `.is_seed()` when the object points at an hypotethic tree+node
    - The previous state `.valid()` was deprecated: its semantics were confusing as it actually could be any of `.readable()` or `.is_seed()`
  - Deprecated also the following methods for `NodeRef`/`ConstNodeRef`:
    ```c++
    RYML_DEPRECATED() bool operator== (std::nullptr_t) const;
    RYML_DEPRECATED() bool operator!= (std::nullptr_t) const;
    RYML_DEPRECATED() bool operator== (csubstr val) const;
    RYML_DEPRECATED() bool operator!= (csubstr val) const;
    ```
  - Added macros and respective cmake options to control error handling:
    - `RYML_USE_ASSERT` - enable assertions regardless of build type. This is disabled by default. This macro was already defined; the current PR adds the cmake option.
    - `RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS` - make the default error handler provided by ryml throw exceptions instead of calling `std::abort()`. This is disabled by default.
  - Also, `RYML_DEBUG_BREAK()` is now enabled only if `RYML_DBG` is defined, as reported in [#362](https://github.com/biojppm/rapidyaml/issues/362).
  - As part of [PR#423](https://github.com/biojppm/rapidyaml/pull/423), to improve linters and codegen:
    - annotate the error handlers with `[[noreturn]]`/`C4_NORETURN`
    - annotate some error sites with `C4_UNREACHABLE_AFTER_ERR()`


### More fixes

- `Tree::arena() const`  was returning a `substr`; this was an error. This function was changed to:
  ```
  csubstr Tree::arena() const;
  substr Tree::arena();
  ```
- Fix [#390](https://github.com/biojppm/rapidyaml/issues/390) - `csubstr::first_real_span()` failed on scientific numbers with one digit in the exponent ([PR#415](https://github.com/biojppm/rapidyaml/pull/415)).
- Fix [#361](https://github.com/biojppm/rapidyaml/issues/361) - parse error on map scalars containing `:` and starting on the next line:
  ```yaml
  ---
  # failed to parse:
  description:
    foo:bar
  ---
  # but this was ok:
  description: foo:bar
  ```
- [PR#368](https://github.com/biojppm/rapidyaml/pull/368) - fix pedantic compiler warnings.
- Fix [#373](https://github.com/biojppm/rapidyaml/issues/373) - false parse error with empty quoted keys in block-style map ([PR#374](https://github.com/biojppm/rapidyaml/pull/374)).
- Fix [#356](https://github.com/biojppm/rapidyaml/issues/356) - fix overzealous check in `emit_as()`. An id may be larger than the tree's size, eg when nodes were removed. ([PR#357](https://github.com/biojppm/rapidyaml/pull/357)).
- Fix [#417](https://github.com/biojppm/rapidyaml/issues/417) - add quickstart example explaining how to avoid precision loss while serializing floats ([PR#420](https://github.com/biojppm/rapidyaml/pull/420)).
- Fix [#380](https://github.com/biojppm/rapidyaml/issues/380) - Debug visualizer .natvis file for Visual Studio was missing `ConstNodeRef` ([PR#383](https://github.com/biojppm/rapidyaml/issues/383)).
- FR [#403](https://github.com/biojppm/rapidyaml/issues/403) - install is now optional when using cmake. The relevant option is `RYML_INSTALL`.


### Python

- Fix [#428](https://github.com/biojppm/rapidyaml/issues/428)/[#412](https://github.com/biojppm/rapidyaml/discussions/412) - Parse errors now throw `RuntimeError` instead of aborting.



### Thanks

- @Neko-Box-Coder
- @jdrouhard
- @dmachaj
