feat(encode): add the InlineTables option
Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
@@ -24,6 +24,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
toml-test tagged JSON from stdin and writes the TOML document it describes.
|
toml-test tagged JSON from stdin and writes the TOML document it describes.
|
||||||
The compliance suite now runs the encoder as well as the decoder, 214
|
The compliance suite now runs the encoder as well as the decoder, 214
|
||||||
encoder cases against the tagged JSON of the valid corpus.
|
encoder cases against the tagged JSON of the valid corpus.
|
||||||
|
- `Encoder.InlineTables(threshold)`: a sub-table whose single-line rendering is
|
||||||
|
at most `threshold` bytes is written as an inline table instead of a header
|
||||||
|
section, which shortens a document of small tables. An array of tables keeps
|
||||||
|
its header form, because its inline form would re-parse as a value array.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ the entire official [toml-test](https://github.com/toml-lang/toml-test) suite:
|
|||||||
- **Cancellation**: every entry point has a `*Context` sibling that honours a
|
- **Cancellation**: every entry point has a `*Context` sibling that honours a
|
||||||
`context.Context`.
|
`context.Context`.
|
||||||
- **Configurable emission**: `Encoder` options for declaration-order output,
|
- **Configurable emission**: `Encoder` options for declaration-order output,
|
||||||
omitting empty arrays, and literal multiline strings.
|
omitting empty arrays, literal multiline strings, and inlining small
|
||||||
|
sub-tables.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|||||||
+30
-3
@@ -429,9 +429,10 @@ the basic form, so the output always re-parses to the same value.
|
|||||||
|
|
||||||
### Inline tables
|
### Inline tables
|
||||||
|
|
||||||
A table element of a value array is written as one `{a = 1, b = 2}` line while
|
A table element of a value array, and a sub-table inlined by
|
||||||
it fits. An inline table that would pass the hundredth column carries newlines
|
[`InlineTables`](#compact-documents), is written as one `{a = 1, b = 2}` line
|
||||||
and a trailing comma instead, which TOML 1.1 allows:
|
while it fits. An inline table that would pass the hundredth column carries
|
||||||
|
newlines and a trailing comma instead, which TOML 1.1 allows:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
arr = [1, {
|
arr = [1, {
|
||||||
@@ -444,6 +445,30 @@ The closing brace and the entries are indented one tab per nesting level, a
|
|||||||
nested table is measured on its own line, and the output re-parses to the same
|
nested table is measured on its own line, and the output re-parses to the same
|
||||||
value either way.
|
value either way.
|
||||||
|
|
||||||
|
### Compact documents
|
||||||
|
|
||||||
|
`InlineTables(threshold)` writes a sub-table as an inline table when its
|
||||||
|
single-line rendering is at most `threshold` bytes, and as a table header
|
||||||
|
section when it is longer. A document of small tables therefore grows shorter:
|
||||||
|
|
||||||
|
```go
|
||||||
|
out, err := interpres.NewEncoder().InlineTables(60).Marshal(cfg)
|
||||||
|
```
|
||||||
|
|
||||||
|
With `60` and a table of three short entries, the same value is written
|
||||||
|
|
||||||
|
```toml
|
||||||
|
server = {host = "127.0.0.1", port = 9090, tls = {on = false}}
|
||||||
|
```
|
||||||
|
|
||||||
|
instead of three lines under a `[server]` header and a `[server.tls]` section.
|
||||||
|
A nested sub-table takes part in the same way, and the whole option is off at
|
||||||
|
`0` or less. Two limits are deliberate. An array of tables keeps the `[[a]]`
|
||||||
|
header form, because its inline form re-parses as a value array and would change
|
||||||
|
the value's Go type. And because an inlined table is a value line, every one of
|
||||||
|
them precedes the first header of its document, so a table inlined next to a
|
||||||
|
header is not read back as part of that header's section.
|
||||||
|
|
||||||
### Cancellation
|
### Cancellation
|
||||||
|
|
||||||
`MarshalContext` and `(*Encoder).MarshalContext` accept a `context.Context`. The
|
`MarshalContext` and `(*Encoder).MarshalContext` accept a `context.Context`. The
|
||||||
@@ -536,12 +561,14 @@ encoder:
|
|||||||
| `GroupByKind(v bool)` | `true` | group entries as scalars, then sub-tables, then arrays of tables; `false` preserves declaration order |
|
| `GroupByKind(v bool)` | `true` | group entries as scalars, then sub-tables, then arrays of tables; `false` preserves declaration order |
|
||||||
| `OmitEmptyArrays()` | off | skip `key = []` for empty scalar arrays |
|
| `OmitEmptyArrays()` | off | skip `key = []` for empty scalar arrays |
|
||||||
| `UseLiteralMultiline(threshold int)` | `0` | emit multi-line strings of at least `threshold` bytes as literal `'''...'''` |
|
| `UseLiteralMultiline(threshold int)` | `0` | emit multi-line strings of at least `threshold` bytes as literal `'''...'''` |
|
||||||
|
| `InlineTables(threshold int)` | `0` | write a sub-table inline when its single-line form is at most `threshold` bytes |
|
||||||
|
|
||||||
```go
|
```go
|
||||||
out, err := interpres.NewEncoder().
|
out, err := interpres.NewEncoder().
|
||||||
GroupByKind(false).
|
GroupByKind(false).
|
||||||
OmitEmptyArrays().
|
OmitEmptyArrays().
|
||||||
UseLiteralMultiline(80).
|
UseLiteralMultiline(80).
|
||||||
|
InlineTables(60).
|
||||||
MarshalContext(ctx, cfg)
|
MarshalContext(ctx, cfg)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -741,7 +741,20 @@ func (e *encoder) emitDoc(doc *tomlDoc, prefix []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// An inlined sub-table is a value line, so it has to precede every
|
||||||
|
// header of this document: a line written after a [header] would be
|
||||||
|
// read back as part of that table.
|
||||||
|
headers := make([]entry, 0, len(tables))
|
||||||
for _, t := range tables {
|
for _, t := range tables {
|
||||||
|
inlined, err := e.writeInlineSubTableIfSmall(t.key, t.doc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !inlined {
|
||||||
|
headers = append(headers, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, t := range headers {
|
||||||
path := append(append([]string{}, prefix...), t.key)
|
path := append(append([]string{}, prefix...), t.key)
|
||||||
e.writeBlankLine()
|
e.writeBlankLine()
|
||||||
e.buf.WriteByte('[')
|
e.buf.WriteByte('[')
|
||||||
@@ -782,6 +795,13 @@ func (e *encoder) emitDoc(doc *tomlDoc, prefix []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case entryTable:
|
case entryTable:
|
||||||
|
inlined, err := e.writeInlineSubTableIfSmall(ent.key, ent.doc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if inlined {
|
||||||
|
continue
|
||||||
|
}
|
||||||
path := append(append([]string{}, prefix...), ent.key)
|
path := append(append([]string{}, prefix...), ent.key)
|
||||||
e.writeBlankLine()
|
e.writeBlankLine()
|
||||||
e.buf.WriteByte('[')
|
e.buf.WriteByte('[')
|
||||||
@@ -1021,6 +1041,107 @@ func (e *encoder) writeInlineIndent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// errInlineArrayOfTables reports an attempt to render an array of tables
|
||||||
|
// inline, which has no form that keeps the value's type.
|
||||||
|
var errInlineArrayOfTables = errors.New("interpres: an array of tables has no inline form")
|
||||||
|
|
||||||
|
// inlinableDoc reports whether doc can be written as an inline table without
|
||||||
|
// changing the type of any value: scalars, value arrays and further sub-tables
|
||||||
|
// are fine, while an array of tables is not, because its inline form would
|
||||||
|
// re-parse as a value array.
|
||||||
|
func inlinableDoc(doc *tomlDoc) bool {
|
||||||
|
for _, ent := range doc.entries {
|
||||||
|
switch ent.kind {
|
||||||
|
case entryArray:
|
||||||
|
return false
|
||||||
|
case entryTable:
|
||||||
|
if !inlinableDoc(ent.doc) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeInlineDocEntry writes one "key = value" binding of an inline table,
|
||||||
|
// without the separator that follows it.
|
||||||
|
func (e *encoder) writeInlineDocEntry(ent entry) error {
|
||||||
|
if err := e.writeKey(ent.key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.buf.WriteString(" = ")
|
||||||
|
switch ent.kind {
|
||||||
|
case entryTable:
|
||||||
|
return e.writeInlineDoc(ent.doc)
|
||||||
|
case entryArray:
|
||||||
|
return errInlineArrayOfTables
|
||||||
|
default:
|
||||||
|
return e.writeValue(ent.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeInlineDoc renders doc as a single-line inline table in entry order, the
|
||||||
|
// order the fields were declared in.
|
||||||
|
func (e *encoder) writeInlineDoc(doc *tomlDoc) error {
|
||||||
|
e.buf.WriteByte('{')
|
||||||
|
for i, ent := range doc.entries {
|
||||||
|
if i > 0 {
|
||||||
|
e.buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
if err := e.writeInlineDocEntry(ent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.buf.WriteByte('}')
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeInlineDocMultiline renders doc with one entry per line and a trailing
|
||||||
|
// comma, the form TOML 1.1 allows for an inline table too long for one line.
|
||||||
|
func (e *encoder) writeInlineDocMultiline(doc *tomlDoc) error {
|
||||||
|
e.buf.WriteString("{\n")
|
||||||
|
e.inlineDepth++
|
||||||
|
for _, ent := range doc.entries {
|
||||||
|
e.writeInlineIndent()
|
||||||
|
if err := e.writeInlineDocEntry(ent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.buf.WriteString(",\n")
|
||||||
|
}
|
||||||
|
e.inlineDepth--
|
||||||
|
e.writeInlineIndent()
|
||||||
|
e.buf.WriteByte('}')
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeInlineSubTableIfSmall writes "key = {…}" for a sub-table whose
|
||||||
|
// single-line rendering fits the compact threshold, and reports whether it did
|
||||||
|
// so. An array of tables is never inlined, because its inline form would
|
||||||
|
// re-parse as a value array and change the value's Go type.
|
||||||
|
func (e *encoder) writeInlineSubTableIfSmall(name string, doc *tomlDoc) (bool, error) {
|
||||||
|
if e.opts.inlineTablesAt <= 0 || !inlinableDoc(doc) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
flat := e.flat()
|
||||||
|
if err := flat.writeInlineDoc(doc); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if flat.buf.Len() > e.opts.inlineTablesAt {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err := e.writeKey(name); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
e.buf.WriteString(" = ")
|
||||||
|
if e.column()+flat.buf.Len() <= e.limit {
|
||||||
|
e.buf.Write(flat.buf.Bytes())
|
||||||
|
} else if err := e.writeInlineDocMultiline(doc); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
e.buf.WriteByte('\n')
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *encoder) writeStringVal(s string) error {
|
func (e *encoder) writeStringVal(s string) error {
|
||||||
if e.opts.literalMultilineAt > 0 && strings.ContainsRune(s, '\n') &&
|
if e.opts.literalMultilineAt > 0 && strings.ContainsRune(s, '\n') &&
|
||||||
len(s) >= e.opts.literalMultilineAt && canBeLiteralMultiline(s) {
|
len(s) >= e.opts.literalMultilineAt && canBeLiteralMultiline(s) {
|
||||||
|
|||||||
+127
@@ -1673,3 +1673,130 @@ func TestMarshalNestedInlineTableBreaksIndependently(t *testing.T) {
|
|||||||
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type inlineTLS struct {
|
||||||
|
On bool `toml:"on"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type inlineServer struct {
|
||||||
|
Host string `toml:"host"`
|
||||||
|
Port int `toml:"port"`
|
||||||
|
TLS inlineTLS `toml:"tls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type inlineBig struct {
|
||||||
|
A int `toml:"a"`
|
||||||
|
B int `toml:"b"`
|
||||||
|
C int `toml:"c"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderInlineTables(t *testing.T) {
|
||||||
|
type Cfg struct {
|
||||||
|
Server inlineServer `toml:"server"`
|
||||||
|
Big inlineBig `toml:"big"`
|
||||||
|
}
|
||||||
|
cfg := Cfg{Server: inlineServer{Host: "127.0.0.1", Port: 9090}, Big: inlineBig{A: 1, B: 2, C: 3}}
|
||||||
|
|
||||||
|
// The default keeps every sub-table a header section.
|
||||||
|
headerForm, err := Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
want := "[server]\nhost = \"127.0.0.1\"\nport = 9090\n\n[server.tls]\non = false\n\n[big]\na = 1\nb = 2\nc = 3\n"
|
||||||
|
if string(headerForm) != want {
|
||||||
|
t.Errorf("default output mismatch:\ngot: %q\nwant: %q", headerForm, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the option both fit the threshold and become inline tables, nested
|
||||||
|
// ones included.
|
||||||
|
out, err := NewEncoder().InlineTables(60).Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
want = "server = {host = \"127.0.0.1\", port = 9090, tls = {on = false}}\nbig = {a = 1, b = 2, c = 3}\n"
|
||||||
|
if string(out) != want {
|
||||||
|
t.Errorf("compact output mismatch:\ngot: %q\nwant: %q", out, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A threshold below the rendering keeps the header form.
|
||||||
|
out, err = NewEncoder().InlineTables(10).Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
if string(out) != string(headerForm) {
|
||||||
|
t.Errorf("small threshold output mismatch:\ngot: %q\nwant: %q", out, headerForm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderInlineTablesOrderAndRoundTrip(t *testing.T) {
|
||||||
|
// An inlined sub-table is a value line, so it precedes every header of the
|
||||||
|
// document; written after a header it would be read back as part of that
|
||||||
|
// table. The compact form and the header form parse to the same tree.
|
||||||
|
type Four struct {
|
||||||
|
A int `toml:"a"`
|
||||||
|
B int `toml:"b"`
|
||||||
|
C int `toml:"c"`
|
||||||
|
D int `toml:"d"`
|
||||||
|
}
|
||||||
|
type Cfg struct {
|
||||||
|
Small inlineTLS `toml:"small"`
|
||||||
|
Big Four `toml:"big"`
|
||||||
|
}
|
||||||
|
cfg := Cfg{Small: inlineTLS{On: true}, Big: Four{A: 1, B: 2, C: 3, D: 4}}
|
||||||
|
|
||||||
|
headerForm, err := Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
compact, err := NewEncoder().InlineTables(20).Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
want := "small = {on = true}\n\n[big]\na = 1\nb = 2\nc = 3\nd = 4\n"
|
||||||
|
if string(compact) != want {
|
||||||
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", compact, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := Parse(compact)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse of the compact output: %v", err)
|
||||||
|
}
|
||||||
|
ref, err := Parse(headerForm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse of the header output: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, ref) {
|
||||||
|
t.Errorf("the compact form changed the tree:\ncompact: %#v\nheaders: %#v", got, ref)
|
||||||
|
}
|
||||||
|
if _, ok := got["big"].(map[string]any); !ok {
|
||||||
|
t.Errorf("big = %#v, want a table", got["big"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderInlineTablesKeepsArraysOfTables(t *testing.T) {
|
||||||
|
// An array of tables has no inline form that keeps the value's type, so the
|
||||||
|
// option leaves it alone and the tree keeps its []map[string]any shape.
|
||||||
|
type Item struct {
|
||||||
|
N int `toml:"n"`
|
||||||
|
}
|
||||||
|
type Cfg struct {
|
||||||
|
Items []Item `toml:"items"`
|
||||||
|
Small inlineTLS `toml:"small"`
|
||||||
|
}
|
||||||
|
cfg := Cfg{Items: []Item{{N: 1}}, Small: inlineTLS{On: true}}
|
||||||
|
out, err := NewEncoder().InlineTables(60).Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
want := "small = {on = true}\n\n[[items]]\nn = 1\n"
|
||||||
|
if string(out) != want {
|
||||||
|
t.Errorf("output mismatch:\ngot: %q\nwant: %q", out, want)
|
||||||
|
}
|
||||||
|
tree, err := Parse(out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse: %v", err)
|
||||||
|
}
|
||||||
|
if _, ok := tree["items"].([]map[string]any); !ok {
|
||||||
|
t.Errorf("items = %#v, want []map[string]any", tree["items"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+24
-2
@@ -234,8 +234,9 @@ type Unmarshaler interface {
|
|||||||
// (offset date-time), and LocalDateTime/LocalDate/LocalTime (local
|
// (offset date-time), and LocalDateTime/LocalDate/LocalTime (local
|
||||||
// variants). A date-time writes its seconds only when the value carries
|
// variants). A date-time writes its seconds only when the value carries
|
||||||
// them, and drops the trailing zeros of a fractional second.
|
// them, and drops the trailing zeros of a fractional second.
|
||||||
// - A table element of a value array is written as an inline table, across
|
// - A table element of a value array, and a sub-table inlined by
|
||||||
// lines when it does not fit one.
|
// Encoder.InlineTables, is written as an inline table, across lines when it
|
||||||
|
// does not fit one.
|
||||||
// - Values implementing Marshaler are encoded by calling MarshalTOML and
|
// - Values implementing Marshaler are encoded by calling MarshalTOML and
|
||||||
// using its result.
|
// using its result.
|
||||||
// - Values implementing encoding.TextMarshaler, and not one of the
|
// - Values implementing encoding.TextMarshaler, and not one of the
|
||||||
@@ -272,6 +273,8 @@ func MarshalContext(ctx context.Context, v any) ([]byte, error) {
|
|||||||
// a nil/empty []Item struct slice is still skipped)
|
// a nil/empty []Item struct slice is still skipped)
|
||||||
// LiteralMultilineAt: 0 (always emit the escaped basic form, never a
|
// LiteralMultilineAt: 0 (always emit the escaped basic form, never a
|
||||||
// literal one)
|
// literal one)
|
||||||
|
// InlineTablesAt: 0 (always emit a table header, never an inline
|
||||||
|
// table)
|
||||||
//
|
//
|
||||||
// Use the chainable option methods to opt out. The option state is private;
|
// Use the chainable option methods to opt out. The option state is private;
|
||||||
// callers that need the underlying knobs reach for the methods rather than
|
// callers that need the underlying knobs reach for the methods rather than
|
||||||
@@ -280,6 +283,7 @@ type Encoder struct {
|
|||||||
groupByKind bool // default true; set via (*Encoder).GroupByKind
|
groupByKind bool // default true; set via (*Encoder).GroupByKind
|
||||||
omitEmptyArrays bool // default false; set via (*Encoder).OmitEmptyArrays
|
omitEmptyArrays bool // default false; set via (*Encoder).OmitEmptyArrays
|
||||||
literalMultilineAt int // default 0; set via (*Encoder).UseLiteralMultiline
|
literalMultilineAt int // default 0; set via (*Encoder).UseLiteralMultiline
|
||||||
|
inlineTablesAt int // default 0; set via (*Encoder).InlineTables
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder returns an Encoder with default options.
|
// NewEncoder returns an Encoder with default options.
|
||||||
@@ -312,6 +316,24 @@ func (e *Encoder) UseLiteralMultiline(threshold int) *Encoder {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InlineTables sets the size limit, in bytes of the single-line rendering, at
|
||||||
|
// which a sub-table is written as an inline table instead of a table header,
|
||||||
|
// which makes a document of small tables shorter. Use 0 or any negative value
|
||||||
|
// to disable (always emit a header).
|
||||||
|
//
|
||||||
|
// A sub-table is inlined only when doing so keeps every value's type: an array
|
||||||
|
// of tables keeps its header form, because its inline form would re-parse as a
|
||||||
|
// value array. An inlined table that does not fit the line is written across
|
||||||
|
// lines, which TOML 1.1 allows.
|
||||||
|
//
|
||||||
|
// With GroupByKind(false) the layout is already for presentation only, and an
|
||||||
|
// inlined table follows the same rule as any other value line: it lands in the
|
||||||
|
// section of the header that precedes it.
|
||||||
|
func (e *Encoder) InlineTables(threshold int) *Encoder {
|
||||||
|
e.inlineTablesAt = threshold
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
// Marshal encodes v to TOML bytes. It is equivalent to calling Marshal with v.
|
// Marshal encodes v to TOML bytes. It is equivalent to calling Marshal with v.
|
||||||
//
|
//
|
||||||
// Marshal is equivalent to MarshalContext with context.Background.
|
// Marshal is equivalent to MarshalContext with context.Background.
|
||||||
|
|||||||
Reference in New Issue
Block a user