fix(encode): keep a []any of tables in the value-array form

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-17 23:10:35 +02:00
parent c485aab227
commit d5327568fb
5 changed files with 48 additions and 0 deletions
+4
View File
@@ -71,6 +71,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
cannot be carried verbatim by the literal form: a run of three single quotes,
a control character, or a lone carriage return. Such values previously
produced output that did not re-parse.
- A `[]any` holding only tables marshals in the value-array form with inline
tables, keeping the type `Parse` produces for such an array. It previously
took the `[[header]]` form, so a round-trip changed the value's type from
`[]any` to `[]map[string]any`.
- Decoding into a `uint` destination checks the type's platform width instead
of only the fixed widths, so a 32-bit `uint` no longer truncates silently;
decoding a finite float beyond the `float32` range is an overflow error
+5
View File
@@ -331,6 +331,11 @@ tree, _ := interpres.Parse([]byte(`arr = [1, {a = 2}, "x"]`))
out, _ := interpres.Marshal(tree) // arr = [1, {a = 2}, "x"]
```
A `[]any` holding only tables keeps the value-array form as well, because that
is the shape `Parse` gives a value array of inline tables; emitting it as
`[[headers]]` would re-parse as `[]map[string]any` and change the value's type
across a round-trip.
### Empty arrays
A nil slice is always omitted. An empty (length 0) array of tables is always
+7
View File
@@ -388,6 +388,13 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, ctx string) error
break
}
}
// A []any of tables is what Parse produces for a value array of inline
// tables; the [[header]] form would re-parse as []map[string]any and so
// change the value's Go type across a round-trip. The header form is
// reserved for typed table slices.
if v.Type().Elem().Kind() == reflect.Interface {
allTables = false
}
if allTables {
subs := make([]*tomlDoc, n)
for i := range n {
+30
View File
@@ -597,6 +597,36 @@ func TestMarshalMixedArrayWithInlineTable(t *testing.T) {
}
}
// A []any of tables is what Parse produces for a value array of inline
// tables; it must stay in the value-array form, or the output would re-parse
// as []map[string]any and the round-trip would change the value's type.
func TestMarshalValueArrayOfTablesStaysInline(t *testing.T) {
for _, doc := range []string{
"0=[{}]",
"a = [{x = 1}, {x = 2}]\n",
"b = [{x = 1}, 2, \"three\"]\n",
} {
tree, err := Parse([]byte(doc))
if err != nil {
t.Fatalf("%s: parse: %v", doc, err)
}
out, err := Marshal(tree)
if err != nil {
t.Fatalf("%s: marshal: %v", doc, err)
}
if bytes.HasPrefix(out, []byte("[[")) {
t.Errorf("%s: emitted the [[header]] form for a value array:\n%s", doc, out)
}
re, err := Parse(out)
if err != nil {
t.Fatalf("%s: re-parse: %v\ndoc:\n%s", doc, err, out)
}
if !tomlEqual(tree, re) {
t.Errorf("%s: round-trip changed the tree:\nwas: %#v\nnow: %#v\ndoc:\n%s", doc, tree, re, out)
}
}
}
func TestMarshalNestedInlineTables(t *testing.T) {
tree := map[string]any{
"mix": []any{
+2
View File
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("0=[{}]")