137 lines
6.8 KiB
Markdown
137 lines
6.8 KiB
Markdown
# toml
|
|
|
|
A deterministic TOML subset encoder/decoder using Go standard library.
|
|
Requires Go 1.27.1.
|
|
|
|
```go
|
|
type Settings struct {
|
|
Name string `toml:"name"`
|
|
Port uint16 `toml:"port"`
|
|
}
|
|
var settings Settings
|
|
err := toml.Unmarshal([]byte("name = \"service\"\nport = 8080\n"), &settings)
|
|
data, err := toml.Marshal(settings)
|
|
```
|
|
|
|
`NewParser(data).Parse()` returns `map[string]any`. `Decode(data, &target)`
|
|
converts an already parsed value. Errors leave the destination unchanged.
|
|
Missing struct fields retain their existing values; present maps and slices
|
|
replace old containers. Existing pointer defaults are retained without writing
|
|
through the original pointer. Fixed arrays require an exact input length.
|
|
Tags use `toml:"name,omitempty"`; an empty tag name
|
|
falls back to the Go field name. Matching is case sensitive. Unknown input keys
|
|
and unexported fields are ignored.
|
|
|
|
## Values and conversions
|
|
|
|
| TOML value | Parsed Go value | Typed destinations |
|
|
| --- | --- | --- |
|
|
| Integer | `int64`, on every architecture | Checked integer and float types |
|
|
| Float | `float64` | Float types; integers only when integral and in range |
|
|
| String | `string` | `string`, `any` |
|
|
| Boolean | `bool` | `bool`, `any` |
|
|
| Array | `[]any` | Slices, fixed arrays, `any` |
|
|
| Table | `map[string]any` | Structs, string-keyed maps, `any` |
|
|
| Array of tables | `[]map[string]any` | Slices and fixed arrays, including pointer elements |
|
|
|
|
Direct `Decode` supports all signed/unsigned numeric widths and named numeric
|
|
types, including the full `uint64` range. Conversions reject overflow, negative
|
|
unsigned inputs, fractional-to-integer truncation, non-finite floats, and
|
|
integer-to-float precision loss. Float64-to-float32 rounding is allowed when in
|
|
range. Strings are not coerced to numbers by this package.
|
|
|
|
`Decode` is transactional, not a deep-copy or synchronization API. Interface
|
|
destinations retain input values (including map and slice references); unchanged
|
|
fields may retain existing references. A nil input is a no-op. Callers own
|
|
snapshot isolation and synchronization when values are shared between goroutines.
|
|
|
|
TOML integer literals have a signed 64-bit range. Consequently `Marshal` rejects
|
|
unsigned values above `MaxInt64`; callers may explicitly encode decimal strings
|
|
and interpret those in their application. Integer parsing and narrow destination
|
|
checks also work on 32-bit systems.
|
|
|
|
## Encoding and round trips
|
|
|
|
`Marshal` accepts a struct or string-keyed map, including pointers to them. Keys
|
|
are sorted. Scalar fields precede nested tables. Table path segments are quoted
|
|
individually, preserving dots, spaces, quotes and Unicode in keys. Mixed arrays
|
|
and nested table values use inline tables when needed. Struct `omitempty` is
|
|
honored; nil pointer/interface fields are omitted. Nil pointer/interface array
|
|
elements error, because TOML has no null value. Nil maps and slices encode as
|
|
empty containers. Duplicate struct tag names error.
|
|
|
|
Basic-string escapes emitted by the encoder (`\b`, `\f`, `\n`, `\r`, `\t`,
|
|
quotes, backslashes, Unicode escapes) decode symmetrically; the TOML 1.1 `\e`
|
|
and `\xHH` decode too. Invalid UTF-8 and unescaped control characters in
|
|
strings are rejected, as are control characters other than tab in comments and
|
|
a carriage return outside CRLF. Encoding and typed decoding
|
|
have recursion bounds (1000 levels), so cyclic traversals fail instead of
|
|
overflowing the stack. Parsing bounds individual value nesting and dotted paths;
|
|
combining paths can still produce trees that exceed the encoder's bound. A
|
|
document may create at most `DefaultMaxTables` (65536) tables, counting every
|
|
dotted-key segment and header part; set `Parser.MaxTables` before `Parse` to
|
|
change it. Errors quote keys and cut long literals, and never repeat a string
|
|
value. `Marshal` writes a table inline once its header path would pass 256
|
|
bytes, so output stays linear in depth.
|
|
|
|
Comments and original formatting are not preserved by `Parse`/`Marshal`; a
|
|
`Document` edits a file in place instead.
|
|
|
|
## Editing a document in place
|
|
|
|
```go
|
|
doc, err := toml.ParseDocument(data)
|
|
err = doc.Decode(&settings)
|
|
unknown := doc.Unmapped(&settings) // []toml.Key no field takes
|
|
removed, err := doc.Delete(toml.Key{"play", "effects"})
|
|
err = doc.Set(toml.Key{"play", "sfx"}, false)
|
|
data = doc.Bytes()
|
|
```
|
|
|
|
`ParseDocument` parses as `Parse` does and keeps the bytes. An edit rewrites only
|
|
the statements it names, so comments, blank lines, order and the spelling of
|
|
every other value stay as written; the result is parsed again, and an edit it
|
|
would not parse after is refused with the document unchanged.
|
|
|
|
- `Set` replaces the value of a key the document sets, keeping the rest of its
|
|
line and its comment. A key it lacks goes after the last key of its table,
|
|
spelled as that key is (`play.mouse` beside `play.hud`), else after the table's
|
|
header, else in a `[table]` appended at the end. A key under an array of
|
|
tables, inside an inline table or array, or naming a table fails. The value is
|
|
encoded as `Marshal` writes one.
|
|
- `Delete` removes the key and every key under it: each statement setting one and
|
|
each header naming one, in every table of an array of tables. It reports
|
|
whether it removed anything; a key inside an inline value fails.
|
|
- `Unmapped` names the keys no field of the destination takes, matched as `Decode`
|
|
matches them (tags, then field names; unexported and `-` fields take nothing),
|
|
each once and sorted. A map or interface destination takes every key under it;
|
|
a key under an array of tables is named without its index.
|
|
- `Key` is a dotted path, one segment per part; `Key.String` spells it as a
|
|
document would, quoting segments that need it.
|
|
|
|
A token's `Pos` and `End` are its byte offsets in the input.
|
|
|
|
## Deliberate subset and deviations
|
|
|
|
- Datetime syntax is unsupported. Use quoted strings and parse them in the
|
|
application; this package does not handle `time.Time` or custom marshal hooks.
|
|
- Literal strings and multiline strings, digit separators, and `inf`/`nan` are
|
|
unsupported.
|
|
- Decimal integer keys (including quoted keys, optional signs and values beyond
|
|
int64) are forbidden. This restriction also applies to the encoder.
|
|
- String escapes invalid in every TOML version are preserved verbatim as a
|
|
documented relaxation.
|
|
- Explicit table headers may reopen existing tables, and dotted keys may extend
|
|
a table a header defined. Inline tables cannot be extended later.
|
|
- Inline tables allow newlines and trailing commas. Arrays require commas,
|
|
including between lines. Top-level statements require newline separation.
|
|
- Signed radix integers and uppercase radix prefixes are accepted extensions.
|
|
- Leading zeros are accepted in decimal numbers; `0123` means decimal 123,
|
|
not octal. Use `0o123` for octal.
|
|
- Embedded struct fields are not promoted. Custom marshal interfaces are not
|
|
supported. Decode input containers are the parser's generic maps/slices.
|
|
|
|
## License
|
|
|
|
BSD-3-Clause
|