AkurAI Build
Menu

Public repository / 439f0dcabf5cdf2b120c7724be895cf1df30507f

AkurAI-Framework / site/content/docs/toml.md

Latest change 021b4bdb77eb9916d2b1c8af86b909d24a92fb93 - docs(toml): document akurai-toml subset, Value type, array-of-tables model by Ólafur Búi Ólafsson

# TOML

The `akurai-toml` crate is a pure-`std`, zero-dependency parser for the slice of
[TOML](https://toml.io) the framework needs to declare data collections in
`backend/collections.toml`. Like every crate in the workspace, it links **no
external crates** and is `#![forbid(unsafe_code)]`.

It parses a deliberately tight subset — just enough for collection config, done
correctly. Anything outside the subset errors cleanly with a line number; the
parser never panics on malformed input.

## The `Value` type

Parsing produces an order-preserving value tree (a `Vec` of pairs, not a map, so
the parsed schema reads the way it was written — and so we stay
dependency-free):

```rust
pub enum Value {
    Table(Vec<(String, Value)>),
    Array(Vec<Value>),
    Str(String),
    Int(i64),
    Float(f64),
    Bool(bool),
}
```

The public API is a single function returning the top-level table:

```rust
pub fn parse(input: &str) -> Result<Value, TomlError>;
```

`parse` always returns `Value::Table(_)` on success. `TomlError` carries a
`message` and the 1-based `line` where parsing gave up.

Convenience accessors mirror `akurai-json`: `get(key)`, `as_table()`,
`as_array()`, `as_str()`, `as_i64()`, `as_f64()`, `as_bool()`.

## Supported subset

- **Key/value lines** — `key = value`. Bare keys are `A-Za-z0-9_-`.
- **Strings** — basic strings `"..."` with the escapes `\"`, `\\`, `\n`, `\t`.
- **Integers** — optional `+`/`-` sign and `_` digit separators (`1_000_000`).
- **Floats** — decimal point and/or exponent (`1.5`, `2.0e3`).
- **Booleans** — `true` / `false`.
- **Arrays** — inline `[a, b, c]`. A trailing comma and newlines inside the
  brackets are allowed, so arrays may span lines.
- **`[table]` headers** — with dotted paths, e.g. `[server.tls]`.
- **`[[array of tables]]` headers** — the key feature for collection config (see
  below), with dotted paths, e.g. `[[collection.field]]`.
- **Dotted keys** — both in headers and as bare keys (`a.b.c = 1`) create the
  intermediate tables.
- **Comments** — `#` to end of line, whole-line or trailing.
- **Blank lines and arbitrary indentation** — TOML ignores indentation; it is
  only there for readability.

## The array-of-tables model

A `[[name]]` header appends a new empty table to the array at `name`, creating
the array on first use. Subsequent key/value lines (and nested `[[name.child]]`
headers) write into that **most recent** element. This is what lets a collection
own an ordered list of fields:

```toml
# a collection
[[collection]]
name = "posts"

  [[collection.field]]
  name = "title"
  type = "text"
  required = true

  [[collection.field]]
  name = "body"
  type = "text"
  embed = true

[[collection]]
name = "notes"
  [[collection.field]]
  name = "n"
  type = "int"
```

parses to (in `Value` terms): a top-level table with one key `collection`, whose
value is an `Array` of two tables. The first has `name = "posts"` and a `field`
array of two tables (`title`, `body`); the second has `name = "notes"` and a
`field` array of one table (`n`). Order is preserved throughout.

```rust
use akurai_toml::{parse, Value};

let doc = parse(src)?;
let collections = doc.get("collection").and_then(Value::as_array).unwrap();
assert_eq!(collections.len(), 2);
let title = collections[0].get("field").and_then(Value::as_array).unwrap()[0]
    .get("name").and_then(Value::as_str);
assert_eq!(title, Some("title"));
```

## Not supported

These error cleanly (with a line number) rather than parsing incorrectly:

- Multi-line basic strings (`"""..."""`)
- Literal strings (`'...'`)
- Datetimes
- Inline tables (`{ a = 1 }`)
- Non-decimal integers (`0xFF`, `0o17`, `0b101`)
- `inf` / `nan` floats
- Unicode (`\uXXXX`) and other escapes beyond `\"`, `\\`, `\n`, `\t`

If the collection config ever needs one of these, extend the subset
deliberately — and add a failing test first.