SCUA

News

All of TOML

August 21, 2026

toml.parse used to read a subset: [sections], and string, integer and boolean values. An array, a float, an inline table or a date came back as an error, so a config file using any of them could not be read at all. That subset is gone. toml.parse now reads TOML 1.0, and toml.encode writes it.

import toml

match toml.parse(text)
  Ok(cfg) -> print((cfg @ "worker")[1] @ "name")
  Error(why) -> print(why)
end

An array is an array you can index and iterate. [[worker]] is an array of tables, in file order. A date is a datetime you can do arithmetic on rather than a string you have to parse again. Integers take the 0x, 0o and 0b bases and 1_000 underscores, floats take inf and nan, and strings come in all four TOML spellings with escapes processed where the spec says they should be.

Replacing the parser instead of extending it was forced. It worked a line at a time, and arrays and inline tables span lines, so those were out of reach from that shape at any amount of effort. What settled it is that the old parser did not only refuse what it could not read. Three inputs parsed to the wrong value and reported nothing: x = """hi""" came back as the string ""hi"", x = "say \"hi\"" kept its backslashes instead of unescaping them, and a [[section]] header became an ordinary table whose name was literally [section]. If you built a workaround for one of those, you can drop it.

Two more silent wrong answers went with it. A date that does not exist used to become a nearby real one, so 1979-99-99 read as 1987-06-07 and 2026-01-32 as the first of February. Both are refused now, leap years counted properly. A document that fails to parse also says which line it failed on rather than only that it failed.

toml.encode sorts its keys, so the same table produces the same text every run and a config file does not reshuffle itself in version control. Exact decimal and money values are written as strings, because TOML's only number types are 64-bit integer and float and either would drop the exactness those types exist to hold. A value with no TOML form at all, like bytes, raises a fault instead of being approximated into one.

Before you round-trip a file, two limits. A bare local time, 07:32:00 with no date, reads as a string, because SCUA has no time-of-day type and inventing a date for it would be worse than saying so. And a date's spelling does not survive a read-modify-write: a datetime is an instant plus an offset and carries no record of having been written date-only, so 2026-08-19 read in and written back out comes out as 2026-08-19T00:00:00Z. Same instant, longer spelling. Where the exact shape of a file matters, edit the text.