Expand description
§tomlini — SAX TOML/INI parser and editor
A zero-dependency, three-tier (core/alloc/std) TOML implementation
that parses into a flat span index instead of a DOM tree. Edits are
byte-range splices on the source string — no decor model, no footguns.
§Quick start
use tomlini::Editor;
let mut doc = tomlini::parse("[server]\nport = 8080\n")?;
// Read values
assert!(doc.has("server.port"));
let raw = doc.get("server.port").unwrap(); // "8080"
let val = doc.get_decoded("server.port").unwrap(); // "8080"
// Edit with the batch editor
doc.edit()
.set("server.port", "9090")
.insert("server", "host", "\"0.0.0.0\"")
.with_above_comment("Bind address")
.commit()?;
let output = doc.to_string();§Feature tiers
| Feature | What you get |
|---|---|
| (none) | parse_into() — classified spans via callback, zero allocations |
alloc | FlatDoc, parse(), full editing API |
std | (default) std::error::Error impls |
§Key types
FlatDoc— parsed document: source string + flat span indexEditor— batch mutation accumulator, commit applies all ops at onceBringAlong— composable flags for what adjacent text to carry when relocatingSpan,SpanKind— classified byte ranges in the sourceParseError— parse error with byte positionValidationMode— lenient/relaxed/strict validation levelsEditError— editor error variants (NotFound,InvalidPath,SectionExists,TableMismatch)SpanSink— core-only callback trait for span emission
§Performance
Parse is 18× faster than toml_edit on a 94-line Cargo.toml (3.3 µs vs
59.5 µs). Batch edits are 2–3× faster than equivalent toml_edit
operations. See crates/benchmarks/ for details.
§Format preservation
Every edit operation preserves comments, whitespace, and formatting unless explicitly overridden. We test for these invariants across all 22 edit operations:
- Comments between keys survive insertions and removals
- Inline comments on modified lines stay in place
- Key formatting (quoted vs bare, dotted vs flat) is never altered
- Value formatting (hex integers, multi-line strings, literal vs basic) passes through unchanged
- Blank-line separators between sections are maintained
- Indentation of new keys copies the neighbor’s indentation
- Removing the last key in a section cleans up trailing whitespace
- Dotted-key headers like
[profiles.dev]survive reordering intact - Comments above keys move with the key when
BringAlongflags are used
These invariants are verified by 11 footgun immunity tests and 8 proptest fuzzers that generate random documents and random edit sequences, asserting that the editor never panics and that successful commits produce re-parseable output.
§Movement & comment control
BringAlong bitflags let you control what adjacent text travels
with a key or section when it moves:
use tomlini::editor::BringAlong;
// Move a key, bringing the comment above it
doc.edit().move_key_bring("a.k", "b.k", BringAlong::COMMENTS_ABOVE).commit()?;
// Promote to root, bringing comments on both sides
doc.edit().promote_key_bring("meta.base",
BringAlong::COMMENTS_ABOVE | BringAlong::COMMENTS_BELOW).commit()?;
// Reorder root entries, keeping section-preceding comments with their section
doc.edit().reorder_root_bring(&["base", "meta"], BringAlong::COMMENTS_ABOVE).commit()?;§Acknowledgments
Built on the excellent work of the toml-rs project:
toml_edit,
toml_datetime, and
toml-test.
§INI files
tomlini parses INI-style configs out of the box — ; comments, bare
values, = separators. No special mode needed: tomlini::parse(ini_str).
§Validation modes
use tomlini::ValidationMode;
doc.validate(ValidationMode::Lenient); // everything accepted
doc.validate(ValidationMode::Relaxed); // structural TOML + INI extensions
doc.validate(ValidationMode::Strict); // full TOML 1.1.0 spec§Container editing
Arrays, inline tables, and array-of-tables are first-class edit targets:
doc.edit()
.array_push("hosts", "\"10.0.0.3\"")
.inline_set("headers", "content-type", "\"text/html\"")
.aot_push("backend", &[("host", "\"10.0.0.4\""), ("port", "9000")])
.aot_remove("backend", 0)
.commit()?;§Core-only usage
Without the alloc feature, the parser emits spans through a callback:
tomlini::parse_into(input, &mut |kind, start, end| {
// Called for every classified span
});Modules§
- editor
- Batch editor for
tomlini.
Structs§
- FlatDoc
- Parse
Error - Span
- Validation
Error - A single validation error with position and description.
Enums§
- Edit
Error - Span
Kind - Validation
Error Kind - The kind of validation problem found.
- Validation
Mode - Validation strictness level.
Traits§
- Span
Sink - Sink trait for receiving classified spans without allocation.
Functions§
- parse
- Parse a TOML document into a
FlatDocfor editing. - parse_
into