feat: Add TOML marshalling API
This commit is contained in:
@@ -55,12 +55,48 @@ port = 9090
|
||||
}
|
||||
```
|
||||
|
||||
### Encode from a struct
|
||||
|
||||
```go
|
||||
out, err := interpres.Marshal(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
```
|
||||
|
||||
writes the same struct back to TOML:
|
||||
|
||||
```toml
|
||||
title = "example"
|
||||
|
||||
[server]
|
||||
host = "127.0.0.1"
|
||||
port = 9090
|
||||
```
|
||||
|
||||
### Untyped tree
|
||||
|
||||
```go
|
||||
tree, err := interpres.Parse(data) // map[string]any
|
||||
tree, err := interpres.Parse(data) // []byte → map[string]any
|
||||
out, err := interpres.Marshal(tree) // map[string]any → []byte
|
||||
```
|
||||
|
||||
### Custom encoding
|
||||
|
||||
Types that need a non-default TOML shape can implement `Marshaler`:
|
||||
|
||||
```go
|
||||
type Port int
|
||||
|
||||
func (p Port) MarshalTOML() (any, error) {
|
||||
return int64(p), nil
|
||||
}
|
||||
```
|
||||
|
||||
The returned value is encoded just like any other value passed to `Marshal`,
|
||||
which means it can be any type `Marshal` itself understands.
|
||||
|
||||
### Strict decoding
|
||||
|
||||
Reject keys that have no matching struct field — useful for catching typos in
|
||||
@@ -95,6 +131,49 @@ skips the field.
|
||||
When decoding into a struct, these map onto the destination's concrete types
|
||||
(any integer/unsigned/float width, slices, nested structs, and `map[string]T`).
|
||||
|
||||
## Encoding
|
||||
|
||||
`Marshal` produces valid TOML 1.0 from any `struct` or `map[string]V` value,
|
||||
applying these rules:
|
||||
|
||||
- The top-level value must be a struct or `map[string]V`. Pointers are
|
||||
followed; a nil top-level pointer is an error.
|
||||
- Struct fields are matched by `toml:"name"` tag (case-insensitive fallback to
|
||||
field name; `toml:"-"` skips). Anonymous (embedded) fields without a tag
|
||||
are inlined.
|
||||
- Maps emit keys in sorted order for deterministic output.
|
||||
- **Output is grouped by kind at every level**: scalars come first, then
|
||||
sub-tables, then arrays of tables. Within each group the order matches
|
||||
struct field declaration order (or, for maps, sorted key order). This means
|
||||
in TOML terms a struct that mixes scalars and sub-tables always lays out
|
||||
scalars at the top of the section followed by the table headers — there is
|
||||
no way to interleave them and still produce a document that re-parses to
|
||||
the same tree.
|
||||
- Slices and arrays of structs or maps become `[[a]]` arrays of tables. Empty
|
||||
or nil arrays of tables are omitted (TOML forbids an empty `[[a]]`); empty
|
||||
arrays of scalars emit as `key = []`.
|
||||
- Other slices and arrays become TOML arrays, including mixed-type `[]any`.
|
||||
- Scalars map to TOML scalars: bool, int64, float64, string, `time.Time`
|
||||
(offset date-time), and the local variants (`LocalDateTime`, `LocalDate`,
|
||||
`LocalTime`).
|
||||
- Strings are always emitted as basic `"..."` strings with the escapes TOML
|
||||
requires (`\"`, `\\`, control characters as `\uXXXX`).
|
||||
- Keys are emitted as bare keys when they match `[A-Za-z0-9_-]+`, quoted
|
||||
otherwise.
|
||||
- Floats always carry a `.` or an exponent (so `1` is always emitted as
|
||||
`1.0`), which preserves the distinction between an integer-typed value and
|
||||
a float-typed value across a `Marshal` → `Parse` round-trip.
|
||||
- Values implementing `Marshaler` are encoded by calling `MarshalTOML` and
|
||||
using its result.
|
||||
- `nil` pointer fields are omitted.
|
||||
|
||||
`Marshal` cannot encode cyclic data structures. The output is not guaranteed
|
||||
to be byte-identical to any TOML document that produced the input value:
|
||||
comments, whitespace, key order (for maps), the choice between `[table]`
|
||||
headers and inline tables, and the basic-vs-literal quoting style are not
|
||||
preserved. The emitted document is, however, guaranteed to be re-parsable by
|
||||
`interpres.Parse` back into an equivalent value tree.
|
||||
|
||||
## TOML 1.0 support
|
||||
|
||||
`interpres` implements the full [TOML 1.0](https://toml.io/en/v1.0.0) grammar:
|
||||
|
||||
Reference in New Issue
Block a user