simpleml 4.0.0

A Rust implementation of a parser/writer for the Simple Markup Language format, as defined by Stenway. See https://dev.stenway.com/SML/. SML builds on top of WSV but allows hierarchical structuring of data.
Documentation
# SimpleML


This crate is a rust implementation of the
[Simple Markup Language](https://www.simpleml.com/) specification. This
specification is built on top of the
[Whitespace Separated Value](https://dev.stenway.com/WSV/Specification.html)
specification and provides a human-friendly configuration file format.

## Patch Notes


### 4.0.0


Updating SMLWriter to take a &Tree<SMLElement> instead of a Tree<SMLElement> to
provide better performance for callers that need to keep the SML data after the
SMLWriter call.

### 3.0.0


Updating the dependency on
[tree_iterators_rs](https://crates.io/crates/tree_iterators_rs) to version 3.2
to get new features.

### 2.0.0


Updating the dependency on
[tree_iterators_rs](https://crates.io/crates/tree_iterators_rs) to version 2.0
for better performance. This is a breaking change and all consumers will need to
update their code to get these performance benefits. If performance is not a
problem for you, there is no reason to switch.

### 1.0.1


Updating the dependency on [whitespacesv](https://crates.io/crates/whitespacesv)
from 1.0.1 to 1.0.2, which
[fixes a panic when writing jagged arrays](https://github.com/mr-adult/WhitespaceSV/issues/1).
Since SML is built on top of WSV, this impacted the SMLWriter as well.

### 1.0.0


This crate is 1.0 now! No breaking changes were introduced in this version, but
it fixes a bug where malformed SML like the following would cause a panic:

```simpleml
Root
    InnerElement
    # No closing tag
End
```

## Parsing


This crate only provides a two APIs for parsing SML files. The
[parse](https://docs.rs/simpleml/latest/simpleml/fn.parse.html) and
[parse_owned](https://docs.rs/simpleml/latest/simpleml/fn.parse_owned.html)
functions will parse the SML input, returning a Result. The Ok variant is a
[Tree](https://docs.rs/tree_iterators_rs/3.5.0/tree_iterators_rs/prelude/struct.Tree.html)
from the [tree_iterators_rs](https://crates.io/crates/tree_iterators_rs) crate
representing the elements of the hierarchy. I have chosen to build on top of it
to provide you with all of the tree traversal utility methods built there when
working with your SML content. I recommend adding
`use tree_iterators_rs::prelude::*;` to the files that handle the SML content to
pull the traversal methods into scope. The only difference between the two APIs
is that [parse](https://docs.rs/simpleml/latest/simpleml/fn.parse.html) uses
Cow<'_, str>'s to represent the SML nodes, and
[parse_owned](https://docs.rs/simpleml/latest/simpleml/fn.parse_owned.html) uses
Strings to represent the SML nodes. If you don't want to deal with lifetimes,
use [parse_owned](https://docs.rs/simpleml/latest/simpleml/fn.parse_owned.html).

Because SML is an extension on top of WSV, I have also pulled in
[whitespacesv](https://crates.io/crates/whitespacesv) as a dependency.

## In-line Declaration


If you plan to include any SimpleML in your rust code or build system, consider
using [simpleml_macro](https://crates.io/crates/simpleml_macro) to maintain
everything in valid SML format. Note that this does not play well with
rust-analyzer and may cause phantom errors to be shown which still compile
successfully.

## Writing


In order to write an SML file, use the
[SMLWriter](https://docs.rs/simpleml/latest/simpleml/struct.SMLWriter.html)
struct. It provides several configuration options, including:

1. any custom end keyword
2. the column alignment of SML attribute WSV tables
3. the indentation string (this must be whitespace)

The list of whitespace characters is defined as follows:

```text
Codepoint 	Name
U+0009 	    Character Tabulation
U+000A 	    Line Feed
U+000B 	    Line Tabulation
U+000C 	    Form Feed
U+000D 	    Carriage Return
U+0020 	    Space
U+0085 	    Next Line
U+00A0 	    No-Break Space
U+1680 	    Ogham Space Mark
U+2000 	    En Quad
U+2001 	    Em Quad
U+2002 	    En Space
U+2003 	    Em Space
U+2004 	    Three-Per-Em Space
U+2005 	    Four-Per-Em Space
U+2006 	    Six-Per-Em Space
U+2007 	    Figure Space
U+2008 	    Punctuation Space
U+2009 	    Thin Space
U+200A 	    Hair Space
U+2028 	    Line Separator
U+2029 	    Paragraph Separator
U+202F 	    Narrow No-Break Space
U+205F 	    Medium Mathematical Space
U+3000 	    Ideographic Space
```

An example of how to use the SMLWriter is as follows:

```rust
use tree_iterators_rs::prelude::*;
use simpleml::{SMLWriter, SMLElement, SMLAttribute};

// Build up our value set
let my_sml_values = Tree {
    value: SMLElement {
        name: "Configuration",
        attributes: Vec::with_capacity(0),
    },
    children: vec![
        Tree {
            value: SMLElement {
                name: "Video",
                attributes: vec![
                    SMLAttribute {
                        name: "Resolution",
                        values: vec![Some("1280"), Some("720")],
                    },
                    SMLAttribute {
                        name: "RefreshRate",
                        values: vec![Some("60")],
                    },
                    SMLAttribute {
                        name: "Fullscreen",
                        values: vec![Some("true")],
                    },
                ],
            },
            children: Vec::new(),
        },
        Tree {
            value: SMLElement {
                name: "Audio",
                attributes: vec![
                    SMLAttribute {
                        name: "Volume",
                        values: vec![Some("100")],
                    },
                    SMLAttribute {
                        name: "Music",
                        values: vec![Some("80")],
                    },
                ],
            },
            children: Vec::new(),
        },
        Tree {
            value: SMLElement {
                name: "Player",
                attributes: vec![SMLAttribute {
                    name: "Name",
                    values: vec![Some("Hero 123")],
                }],
            },
            children: Vec::new(),
        },
    ],
};

// actually write the values
let str = SMLWriter::new(my_sml_values)
    // Setting up a custom end keyword
    .with_end_keyword(Some("my_custom_end_keyword"))
    // Using 8 spaces as the indent string. The default is 4 spaces.
    .indent_with("        ")
    .unwrap()
    // Align the WSV tables to the right.
    .align_columns(whitespacesv::ColumnAlignment::Right)
    .to_string()
    .unwrap();

/// Result:
/// Configuration
///         Video
///                  Resolution 1280 720
///                 RefreshRate   60
///                  Fullscreen true
///         my_custom_end_keyword
///         Audio
///                 Volume 100
///                  Music  80
///         my_custom_end_keyword
///         Player
///                 Name "Hero 123"
///         my_custom_end_keyword
/// my_custom_end_keyword
println!("{}", str);
```