Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Read and write TOML

std.toml parses TOML 1.0 documents, such as configuration files and project manifests, into a value tree, and writes a tree back as TOML text. Every call takes explicit limits.

Parse a configuration file

import std.toml
from std.toml import Entry, Toml

def show(entries: &list[Entry], indent: &str) -> Result[(), AllocError | IoError]:
    for entry in entries:
        name = (indent + entry.key)?
        match &entry.value:
            case Toml.Table(inner):
                print((name + ":")?)?
                show(inner, &(indent + "  ")?)?
            case Toml.Text(text):
                print(name, "is the text", text)?
            case Toml.Int(number):
                print(name, "is the integer", *number)?
            case Toml.Array(items):
                print(name, "has", len(items), "items")?
            case Toml.DateTime(moment):
                print(name, "is a date in", moment.year)?
            case _:
                print(name, "is something else")?
    Ok(())

def main() -> Result[(), AllocError | IoError | std.toml.TomlError]:
    bounds = std.toml.limits()
    text = "# Service settings\ntitle = \"cache\"\n\n[server]\nhost = \"0.0.0.0\"\nport = 8080\n\n[server.tls]\nenabled = true\n\n[[backend]]\nurl = \"http://a.internal\"\n\n[[backend]]\nurl = \"http://b.internal\"\n\n[release]\ndate = 2026-10-01\n"
    value = std.toml.parse_text(text, &bounds)?
    match &value:
        case Toml.Table(root):
            show(root, "")?
            print(std.toml.find(root, "server"), std.toml.find(root, "client"))?
        case _:
            print("a document is always a table")?
    Ok(())
title is the text cache
server:
  host is the text 0.0.0.0
  port is the integer 8080
  tls:
    enabled is something else
backend has 2 items
release:
  date is a date in 2026
Option[i64].Some(1) Option[i64].Nothing

A document is always a Toml.Table: a list[Entry] in source order, where each entry has a key and a value. [server] and [server.tls] become nested tables, and each [[backend]] adds one table to the array backend. find returns the index of the first entry with a key.

Toml has one variant per TOML type: Bool, Int, Float, Text, DateTime, Array, and Table. Integers are i64. A DateTime holds the date and time fields, its offset from UTC in minutes, and a kind that says which parts the text gave: an offset date-time, a local date-time, a local date, or a local time.

Errors say where

A TomlError carries a fault, the byte offset, and a line and column that both start at 1.

import std.toml
from std.toml import Limits

def attempt(text: &str, bounds: &Limits) -> Result[(), IoError]:
    match std.toml.parse_text(text, bounds):
        case Ok(_):
            print("ok")?
        case Err(error):
            print(error.fault, "at line", error.line, "column", error.column)?
    Ok(())

def main() -> Result[(), AllocError | IoError]:
    bounds = std.toml.limits()
    attempt("name = \"Tom\"\nname = \"Pradyun\"", &bounds)?
    attempt("[fruit]\na = 1\n[fruit]\nb = 2", &bounds)?
    attempt("point = { x = 1 }\npoint.y = 2", &bounds)?
    attempt("port = 08080", &bounds)?
    attempt("day = 2026-02-29", &bounds)?
    attempt("key = \"unterminated", &bounds)?
    Ok(())
std.toml.TomlFault.DuplicateKey at line 2 column 1
std.toml.TomlFault.DuplicateTable at line 3 column 1
std.toml.TomlFault.KeyConflict at line 2 column 1
std.toml.TomlFault.InvalidNumber at line 1 column 8
std.toml.TomlFault.InvalidDateTime at line 1 column 7
std.toml.TomlFault.UnexpectedEnd at line 1 column 20

TOML forbids defining a key or table twice, and an inline table such as { x = 1 } is complete as written, so point.y cannot add to it. Integers may not have leading zeros, and dates must exist. An error about a key or a table points at the start of the line that repeats it.

Write a tree as TOML

import std.toml
from std.toml import Entry, Toml

def main() -> Result[(), AllocError | IoError | std.toml.TomlError]:
    bounds = std.toml.limits()
    mut package = list[Entry]()?
    package.append(Entry("name", Toml.Text("player")))?
    package.append(Entry("version", Toml.Text("0.1.0")))?
    mut authors = list[Toml]()?
    authors.append(Toml.Text("Ada"))?
    package.append(Entry("authors", Toml.Array(authors)))?
    mut root = list[Entry]()?
    root.append(Entry("package", Toml.Table(package)))?
    root.append(Entry("manifest-version", Toml.Int(1)))?
    text = std.toml.encode_text(&Toml.Table(root), &bounds)?
    print(text.rstrip()?)?
    Ok(())
manifest-version = 1

[package]
name = "player"
version = "0.1.0"
authors = ["Ada"]

The writer puts each table’s plain keys first and its tables after them as [section] headers, because a key written after a header would belong to that header’s table. Parsing the output gives back the same values. The writer does not keep comments or the original layout, so it suits generated files rather than editing a file a person maintains.

Update a manifest while keeping comments

For a file maintained by a person, use a Document. Replacing a value keeps the surrounding spelling and comments:

import std.toml
from std.toml import Toml

def main() -> Result[(), AllocError | IoError | std.toml.TomlError]:
    source = "# release settings\n[package]\nversion = '0.1.0' # public version\n"
    mut document = std.toml.document_text(source, &std.toml.limits())?
    document.set(&["package", "version"]?, &Toml.Text("0.2.0"))?
    document.insert(&["package", "publish"]?, &Toml.Bool(False))?
    print(document.text()?.rstrip()?)?
    Ok(())
# release settings
[package]
version = "0.2.0" # public version
publish = false

Paths list decoded keys, so a key containing a dot is one list element. get reads an owned value; remove deletes a key or a whole section. Failed edits leave the document unchanged. Arrays and inline tables are replaced as whole values; this API does not edit individual array rows or inline fields. See the editing reference for the exact preservation rules and costs.

The std.toml reference lists every fault, limit, and cost.