# SML
`SML` is a simple markup language designed to convert human readable information into Rust
types, focusing on simplicity, usability and hands-on control. Its optimal usage is in loading
config files and schemas.
The format looks like
```text
hobbit:
name: "Frodo Baggins"
age: "98"
friends:
hobbit:
name: "Bilbo Baggins"
age: "176"
hobbit:
name: "Samwise Gamgee"
age: "66"
```
## Data Format Rules
1. Indentation has meaning and is 4 spaces, relative to the top key.
2. All values must be double quoted.
3. Every key/value combination must be nested in a key. For example
```rust
hobbit: "Frodo"
```
by itself is invalid. It can be written:
```rust
hobbit:
name: "Frodo"
```
The motivation behind this is for the data format to distinguish clearly
between whole data structures, which are headed by a key only, and parts of a
data structure which are either key/value pairs, representing fields or
variants, or other data-structures, which again are headed by a key only.
4. Separation of lines has meaning.
5. Keys must not include but must be followed by a colon `:`.
6. Double quotes in values must be escaped using `\"`.
7. Everything after the second double quote is ignored (and can be used for commenting).
8. Empty lines or lines with whitespace only are ignored.
## Example 1: From `Small`-formatted string to your data-structure.
The following two examples should cover 90 percent of use cases.
data-structure.
```rust
use small::{Small, FromSmall, SmallError};
#[derive(Debug)]
struct Hobbit {
name: String,
age: u32,
friends: Vec<Hobbit>,
bicycle: Option<String>,
}
impl FromSmall for Hobbit {
fn from_small(s: &SmallRef) -> Result<Self, SmallError> {
Ok(Self {
name: String::path(&s, "hobbit::name")?,
age: u32::path(&s, "hobbit::age")?,
friends: Vec::<Hobbit>::path(&s, "hobbit::friends::hobbit")?,
bicycle: Option::<String>::path(&s, "hobbit::bicycle")?,
})
}
}
fn main() {
let s = r#"
hobbit:
name: "Frodo Baggins"
age: "98"
friends:
hobbit:
name: "Bilbo Baggins"
age: "176"
hobbit:
name: "Samwise Gamgee"
age: "66""#;
let frodo = Hobbit::from_str_debug(s);
}
```
## Example 2: From your data-structure to a Small-formatted string.
To convert from a data-structure to a string,
```rust
use sml::{Small, ToSmall, SmallError};
#[derive(Debug)]
struct Hobbit {
name: String,
age: u32,
friends: Vec<Hobbit>,
bicycle: Option<String>,
}
impl ToSmall for Hobbit {
fn to_small(&self, key: &str) -> Result<Small, SmallError> {
Small::join("hobbit", &vec!(
self.name.to_small("name")?,
self.age.to_small("age")?,
self.friends.to_small("friends")?,
self.bicycle.to_small("bicycle")?,
))
}
}
println!("{}", frodo::key("hobbit"));
// hobbit:
// name: "Frodo Baggins"
// age: "98"
// friends:
// hobbit:
// name: "Bilbo Baggins"
// age: "176"
// hobbit:
// name: "Samwise Gamgee"
// age: "66"
```
## Basic Organization
```text
--------------------------from_str()----------------------------
| | | |
| | FromSmall trait | |
| | --from_small()-- | -----to_ref()---- --from_str()--- |
| | | | | | | | | |
v v v | | v | v | |
---------- ------------ --------- ----------
| Hobbit | | SmallRef |-ref into->| Small | | String |
---------- ------------ --------- ----------
^ ^ | ^
| | | |
------------ to_small()----------------- --to_string()--
ToSmall trait
```
## Functions on `Small`
```rust
join(key: &str, subs: &Vec<Small>) -> Result<Small, SmallError>
```
Returns a `Small` type given a key and a `Vec` of `Small`s. The `Vec` of `Small`s are
indented below the key. See example 2.
```rust
key_value(key: &str, value: String) -> Result<Small, SmallError>
```
Returns a `Small` type that consists of one key-value pair.
```rust
to_ref(&self) -> SmallRef
```
Converts `self` into a `SmallRef`.
## `FromSmall` Trait
Types that implement the `FromSmall` trait can be constructed from a `Small`-formatted string.
Required function:
```rust
from_small(slice: &SmallRef) -> Result<Self, SmallError>
```
The `from_small()` function describes how to create a data-structure from the parts of
`SmallRef`. See example 1 for canonical usage.
```rust
path(small: &SmallRef, key_path: &str) -> Result<Self, SmallError>
```
Reduces `SmallRef` to the `key_path` and then uses the `FromSmall` trait to convert to the
receiver type.
```rust
from_str(s: &str) -> Result<Self, SmallError>
```
Top level function that convert a `Small`-formatted string into the receiver.
```rust
from_str_debug(s: &str) -> Self
```
Top level function that converts a `Small`-formatted string into the receiver giving helpful
error messages for debugging.
## `ToSmall` Trait
The `ToSmall` trait is implemented for `String`s, `Vec<T>`, `Option<T>`, `bool` and all the
standard library integer and float types.
Required function:
```rust
fn to_small(&self, key: &str) -> Result<Small, SmallError>;
```
Converts a receiver that implements `ToSmall` into a `Small`-formatted string. `key` can be
overridden in the implementation, depending on whether you want to data-structure itself to
set the key name or whether you want to context of the `Small`-formatted string to set the
key name.