• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H27-Jul-2021-

benchmark/H27-Jul-2021-

internal/H27-Jul-2021-

.dockerignoreH A D27-Jul-202138

.gitattributesH A D27-Jul-202150

.gitignoreH A D27-Jul-2021102

.golangci.tomlH A D27-Jul-20211.4 KiB

CONTRIBUTING.mdH A D27-Jul-20216.8 KiB

LICENSEH A D27-Jul-20211.1 KiB

README.mdH A D27-Jul-202111.8 KiB

ci.shH A D27-Jul-20216.1 KiB

decode.goH A D27-Jul-20216.8 KiB

doc.goH A D27-Jul-202176

errors.goH A D27-Jul-20216 KiB

errors_test.goH A D27-Jul-20213.8 KiB

fast_test.goH A D27-Jul-20211.9 KiB

go.modH A D27-Jul-2021176

go.sumH A D27-Jul-20211.1 KiB

localtime.goH A D27-Jul-20212.6 KiB

localtime_test.goH A D27-Jul-20212.7 KiB

marshaler.goH A D27-Jul-202115.8 KiB

marshaler_test.goH A D27-Jul-202114.1 KiB

parser.goH A D27-Jul-202120.4 KiB

parser_test.goH A D27-Jul-20217.6 KiB

scanner.goH A D27-Jul-20214.6 KiB

strict.goH A D27-Jul-20211.7 KiB

toml.abnfH A D27-Jul-20216.9 KiB

toml_testgen_support_test.goH A D27-Jul-20212.9 KiB

toml_testgen_test.goH A D27-Jul-202121.6 KiB

types.goH A D27-Jul-2021381

unmarshaler.goH A D27-Jul-202126.1 KiB

unmarshaler_test.goH A D27-Jul-202143.1 KiB

README.md

1# go-toml v2
2
3Go library for the [TOML](https://toml.io/en/) format.
4
5This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
6
7## Development status
8
9This is the upcoming major version of go-toml. It is currently in active
10development. As of release v2.0.0-beta.1, the library has reached feature parity
11with v1, and fixes a lot known bugs and performance issues along the way.
12
13If you do not need the advanced document editing features of v1, you are
14encouraged to try out this version.
15
16[�� Roadmap for v2](https://github.com/pelletier/go-toml/discussions/506)
17
18[�� Bug Reports](https://github.com/pelletier/go-toml/issues)
19
20[�� Anything else](https://github.com/pelletier/go-toml/discussions)
21
22## Documentation
23
24Full API, examples, and implementation notes are available in the Go documentation.
25
26[![Go Reference](https://pkg.go.dev/badge/github.com/pelletier/go-toml/v2.svg)](https://pkg.go.dev/github.com/pelletier/go-toml/v2)
27
28## Import
29
30```go
31import "github.com/pelletier/go-toml/v2"
32```
33
34See [Modules](#Modules).
35
36## Features
37
38### Stdlib behavior
39
40As much as possible, this library is designed to behave similarly as the
41standard library's `encoding/json`.
42
43### Performance
44
45While go-toml favors usability, it is written with performance in mind. Most
46operations should not be shockingly slow. See [benchmarks](#benchmarks).
47
48### Strict mode
49
50`Decoder` can be set to "strict mode", which makes it error when some parts of
51the TOML document was not prevent in the target structure. This is a great way
52to check for typos. [See example in the documentation][strict].
53
54[strict]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#example-Decoder.SetStrict
55
56### Contextualized errors
57
58When decoding errors occur, go-toml returns [`DecodeError`][decode-err]), which
59contains a human readable contextualized version of the error. For example:
60
61```
622| key1 = "value1"
633| key2 = "missing2"
64 | ~~~~ missing field
654| key3 = "missing3"
665| key4 = "value4"
67```
68
69[decode-err]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#DecodeError
70
71### Local date and time support
72
73TOML supports native [local date/times][ldt]. It allows to represent a given
74date, time, or date-time without relation to a timezone or offset. To support
75this use-case, go-toml provides [`LocalDate`][tld], [`LocalTime`][tlt], and
76[`LocalDateTime`][tldt]. Those types can be transformed to and from `time.Time`,
77making them convenient yet unambiguous structures for their respective TOML
78representation.
79
80[ldt]: https://toml.io/en/v1.0.0#local-date-time
81[tld]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDate
82[tlt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalTime
83[tldt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDateTime
84
85## Getting started
86
87Given the following struct, let's see how to read it and write it as TOML:
88
89```go
90type MyConfig struct {
91      Version int
92      Name    string
93      Tags    []string
94}
95```
96
97### Unmarshaling
98
99[`Unmarshal`][unmarshal] reads a TOML document and fills a Go structure with its
100content. For example:
101
102```go
103doc := `
104version = 2
105name = "go-toml"
106tags = ["go", "toml"]
107`
108
109var cfg MyConfig
110err := toml.Unmarshal([]byte(doc), &cfg)
111if err != nil {
112      panic(err)
113}
114fmt.Println("version:", cfg.Version)
115fmt.Println("name:", cfg.Name)
116fmt.Println("tags:", cfg.Tags)
117
118// Output:
119// version: 2
120// name: go-toml
121// tags: [go toml]
122```
123
124[unmarshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Unmarshal
125
126### Marshaling
127
128[`Marshal`][marshal] is the opposite of Unmarshal: it represents a Go structure
129as a TOML document:
130
131```go
132cfg := MyConfig{
133      Version: 2,
134      Name:    "go-toml",
135      Tags:    []string{"go", "toml"},
136}
137
138b, err := toml.Marshal(cfg)
139if err != nil {
140      panic(err)
141}
142fmt.Println(string(b))
143
144// Output:
145// Version = 2
146// Name = 'go-toml'
147// Tags = ['go', 'toml']
148```
149
150[marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal
151
152## Benchmarks
153
154Execution time speedup compared to other Go TOML libraries:
155
156<table>
157    <thead>
158        <tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
159    </thead>
160    <tbody>
161        <tr><td>Marshal/HugoFrontMatter</td><td>2.0x</td><td>2.0x</td></tr>
162        <tr><td>Marshal/ReferenceFile/map</td><td>1.8x</td><td>2.0x</td></tr>
163        <tr><td>Marshal/ReferenceFile/struct</td><td>2.7x</td><td>2.7x</td></tr>
164        <tr><td>Unmarshal/HugoFrontMatter</td><td>3.0x</td><td>2.6x</td></tr>
165        <tr><td>Unmarshal/ReferenceFile/map</td><td>3.0x</td><td>3.1x</td></tr>
166        <tr><td>Unmarshal/ReferenceFile/struct</td><td>5.9x</td><td>6.6x</td></tr>
167     </tbody>
168</table>
169<details><summary>See more</summary>
170<p>The table above has the results of the most common use-cases. The table below
171contains the results of all benchmarks, including unrealistic ones. It is
172provided for completeness.</p>
173
174<table>
175    <thead>
176        <tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
177    </thead>
178    <tbody>
179        <tr><td>Marshal/SimpleDocument/map</td><td>1.7x</td><td>2.1x</td></tr>
180        <tr><td>Marshal/SimpleDocument/struct</td><td>2.6x</td><td>2.9x</td></tr>
181        <tr><td>Unmarshal/SimpleDocument/map</td><td>4.1x</td><td>2.9x</td></tr>
182        <tr><td>Unmarshal/SimpleDocument/struct</td><td>6.3x</td><td>4.1x</td></tr>
183        <tr><td>UnmarshalDataset/example</td><td>3.5x</td><td>2.4x</td></tr>
184        <tr><td>UnmarshalDataset/code</td><td>2.2x</td><td>2.8x</td></tr>
185        <tr><td>UnmarshalDataset/twitter</td><td>2.8x</td><td>2.1x</td></tr>
186        <tr><td>UnmarshalDataset/citm_catalog</td><td>2.3x</td><td>1.5x</td></tr>
187        <tr><td>UnmarshalDataset/config</td><td>4.2x</td><td>3.2x</td></tr>
188        <tr><td>[Geo mean]</td><td>3.0x</td><td>2.7x</td></tr>
189     </tbody>
190</table>
191<p>This table can be generated with <code>./ci.sh benchmark -a -html</code>.</p>
192</details>
193
194## Modules
195
196go-toml uses Go's standard modules system.
197
198Installation instructions:
199
200- Go ≥ 1.16: Nothing to do. Use the import in your code. The `go` command deals
201  with it automatically.
202- Go ≥ 1.13: `GO111MODULE=on go get github.com/pelletier/go-toml/v2`.
203
204In case of trouble: [Go Modules FAQ][mod-faq].
205
206[mod-faq]: https://github.com/golang/go/wiki/Modules#why-does-installing-a-tool-via-go-get-fail-with-error-cannot-find-main-module
207
208## Migrating from v1
209
210This section describes the differences between v1 and v2, with some pointers on
211how to get the original behavior when possible.
212
213### Decoding / Unmarshal
214
215#### Automatic field name guessing
216
217When unmarshaling to a struct, if a key in the TOML document does not exactly
218match the name of a struct field or any of the `toml`-tagged field, v1 tries
219multiple variations of the key ([code][v1-keys]).
220
221V2 instead does a case-insensitive matching, like `encoding/json`.
222
223This could impact you if you are relying on casing to differentiate two fields,
224and one of them is a not using the `toml` struct tag. The recommended solution
225is to be specific about tag names for those fields using the `toml` struct tag.
226
227[v1-keys]: https://github.com/pelletier/go-toml/blob/a2e52561804c6cd9392ebf0048ca64fe4af67a43/marshal.go#L775-L781
228
229#### Ignore preexisting value in interface
230
231When decoding into a non-nil `interface{}`, go-toml v1 uses the type of the
232element in the interface to decode the object. For example:
233
234```go
235type inner struct {
236  B interface{}
237}
238type doc struct {
239  A interface{}
240}
241
242d := doc{
243  A: inner{
244    B: "Before",
245  },
246}
247
248data := `
249[A]
250B = "After"
251`
252
253toml.Unmarshal([]byte(data), &d)
254fmt.Printf("toml v1: %#v\n", d)
255
256// toml v1: main.doc{A:main.inner{B:"After"}}
257```
258
259In this case, field `A` is of type `interface{}`, containing a `inner` struct.
260V1 sees that type and uses it when decoding the object.
261
262When decoding an object into an `interface{}`, V2 instead disregards whatever
263value the `interface{}` may contain and replaces it with a
264`map[string]interface{}`. With the same data structure as above, here is what
265the result looks like:
266
267```go
268toml.Unmarshal([]byte(data), &d)
269fmt.Printf("toml v2: %#v\n", d)
270
271// toml v2: main.doc{A:map[string]interface {}{"B":"After"}}
272```
273
274This is to match `encoding/json`'s behavior. There is no way to make the v2
275decoder behave like v1.
276
277#### Values out of array bounds ignored
278
279When decoding into an array, v1 returns an error when the number of elements
280contained in the doc is superior to the capacity of the array. For example:
281
282```go
283type doc struct {
284  A [2]string
285}
286d := doc{}
287err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
288fmt.Println(err)
289
290// (1, 1): unmarshal: TOML array length (3) exceeds destination array length (2)
291```
292
293In the same situation, v2 ignores the last value:
294
295```go
296err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
297fmt.Println("err:", err, "d:", d)
298// err: <nil> d: {[one two]}
299```
300
301This is to match `encoding/json`'s behavior. There is no way to make the v2
302decoder behave like v1.
303
304#### Support for `toml.Unmarshaler` has been dropped
305
306This method was not widely used, poorly defined, and added a lot of complexity.
307A similar effect can be achieved by implementing the `encoding.TextUnmarshaler`
308interface and use strings.
309
310#### Support for `default` struct tag has been dropped
311
312This feature adds complexity and a poorly defined API for an effect that can be
313accomplished outside of the library.
314
315It does not seem like other format parsers in Go support that feature (the
316project referenced in the original ticket #202 has not been updated since 2017).
317Given that go-toml v2 should not touch values not in the document, the same
318effect can be achieved by pre-filling the struct with defaults (libraries like
319[go-defaults][go-defaults] can help). Also, string representation is not well
320defined for all types: it creates issues like #278.
321
322The recommended replacement is pre-filling the struct before unmarshaling.
323
324[go-defaults]: https://github.com/mcuadros/go-defaults
325
326### Encoding / Marshal
327
328#### Default struct fields order
329
330V1 emits struct fields order alphabetically by default. V2 struct fields are
331emitted in order they are defined. For example:
332
333```go
334type S struct {
335	B string
336	A string
337}
338
339data := S{
340	B: "B",
341	A: "A",
342}
343
344b, _ := tomlv1.Marshal(data)
345fmt.Println("v1:\n" + string(b))
346
347b, _ = tomlv2.Marshal(data)
348fmt.Println("v2:\n" + string(b))
349
350// Output:
351// v1:
352// A = "A"
353// B = "B"
354
355// v2:
356// B = 'B'
357// A = 'A'
358```
359
360There is no way to make v2 encoder behave like v1. A workaround could be to
361manually sort the fields alphabetically in the struct definition.
362
363#### No indentation by default
364
365V1 automatically indents content of tables by default. V2 does not. However the
366same behavior can be obtained using [`Encoder.SetIndentTables`][sit]. For example:
367
368```go
369data := map[string]interface{}{
370	"table": map[string]string{
371		"key": "value",
372	},
373}
374
375b, _ := tomlv1.Marshal(data)
376fmt.Println("v1:\n" + string(b))
377
378b, _ = tomlv2.Marshal(data)
379fmt.Println("v2:\n" + string(b))
380
381buf := bytes.Buffer{}
382enc := tomlv2.NewEncoder(&buf)
383enc.SetIndentTables(true)
384enc.Encode(data)
385fmt.Println("v2 Encoder:\n" + string(buf.Bytes()))
386
387// Output:
388// v1:
389//
390// [table]
391//   key = "value"
392//
393// v2:
394// [table]
395// key = 'value'
396//
397//
398// v2 Encoder:
399// [table]
400//   key = 'value'
401```
402
403[sit]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Encoder.SetIndentTables
404
405#### Keys and strings are single quoted
406
407V1 always uses double quotes (`"`) around strings and keys that cannot be
408represented bare (unquoted). V2 uses single quotes instead by default (`'`),
409unless a character cannot be represented, then falls back to double quotes.
410
411There is no way to make v2 encoder behave like v1.
412
413#### `TextMarshaler` emits as a string, not TOML
414
415Types that implement [`encoding.TextMarshaler`][tm] can emit arbitrary TOML in
416v1. The encoder would append the result to the output directly. In v2 the result
417is wrapped in a string. As a result, this interface cannot be implemented by the
418root object.
419
420There is no way to make v2 encoder behave like v1.
421
422[tm]: https://golang.org/pkg/encoding/#TextMarshaler
423
424## License
425
426The MIT License (MIT). Read [LICENSE](LICENSE).
427