Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
arp242 committed Aug 2, 2021
1 parent 8162ef3 commit 5f40317
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 91 deletions.
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,16 @@ representations. (There is an example of this below.)

Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0).

Documentation: https://pkg.go.dev/github.com/BurntSushi/toml
Documentation: https://godocs.io/github.com/BurntSushi/toml

This library requires Go 1.13 or newer; install it with:

```bash
go get github.com/BurntSushi/toml
```
$ go get github.com/BurntSushi/toml

Try the TOML validator:
It also comes with a TOML validator CLI tool:

```bash
go get github.com/BurntSushi/toml/cmd/tomlv
tomlv some-toml-file.toml
```
$ go get github.com/BurntSushi/toml/cmd/tomlv
$ tomlv some-toml-file.toml

### Testing

Expand Down
58 changes: 30 additions & 28 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,16 @@ func Unmarshal(p []byte, v interface{}) error {
}

// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
// This type can be used for any value, which will cause decoding to be delayed.
// You can use the PrimitiveDecode() function to "manually" decode these values.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
// NOTE: The underlying representation of a `Primitive` value is subject to
// change. Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
// NOTE: Primitive values are still parsed, so using them will only avoid the
// overhead of reflection. They can be useful when you don't know the exact type
// of TOML data until runtime.
type Primitive struct {
undecoded interface{}
context Key
Expand All @@ -58,26 +57,25 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
return md.unify(primValue.undecoded, rvalue(v))
}

// Decode TOML data.
// Decoder decodes TOML data.
//
// TOML tables correspond to Go structs or maps (dealer's choice – they can be
// used interchangeably).
//
// TOML table arrays correspond to either a slice of structs or a slice of maps.
//
// TOML datetimes correspond to Go `time.Time` values. Local datetimes are
// parsed in the local timezone and have the Location set to toml.LocalDatetime.
// Local dates and times have the Location set to toml.LocalDate and
// toml.LocalTime.
// TOML datetimes correspond to Go time.Time values. Local datetimes are parsed
// in the local timezone and have the Location set to the decoders's Timezone
// value. This defaults to this computer's local timezone if not given.
//
// All other TOML types (float, string, int, bool and array) correspond to the
// obvious Go types.
//
// An exception to the above rules is if a type implements the
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
// (floats, strings, integers, booleans and datetimes) will be converted to a
// byte string and given to the value's UnmarshalText method. See the
// Unmarshaler example for a demonstration with time duration strings.
// An exception to the above rules is if a type implements the TextUnmarshaler
// interface, in which case any primitive TOML value (floats, strings, integers,
// booleans, datetimes) will be converted to a []byte and given to the value's
// UnmarshalText method. See the Unmarshaler example for a demonstration with
// time duration strings.
//
// Key mapping
//
Expand All @@ -96,6 +94,10 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
// cyclic type is passed.
type Decoder struct {
r io.Reader

// Timezone to use for local times. Defaults to this computer's local
// timezone if nil.
//Timezone *time.Location
}

// NewDecoder creates a new Decoder.
Expand Down Expand Up @@ -133,15 +135,15 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) {

// Decode the TOML data in to the pointer v.
//
// See Decoder for the full documentation.
// See the documentation on Decoder for a description of the decoding process.
func Decode(data string, v interface{}) (MetaData, error) {
return NewDecoder(strings.NewReader(data)).Decode(v)
}

// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
fp, err := os.Open(fpath)
// contents of the file at path and decode it for you.
func DecodeFile(path string, v interface{}) (MetaData, error) {
fp, err := os.Open(path)
if err != nil {
return MetaData{}, err
}
Expand Down Expand Up @@ -180,13 +182,13 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
if v, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
return md.unifyText(data, v)
}
// BUG(burntsushi)
// TODO:
// The behavior here is incorrect whenever a Go type satisfies the
// encoding.TextUnmarshaler interface but also corresponds to a TOML
// hash or array. In particular, the unmarshaler should only be applied
// to primitive TOML values. But at this point, it will be applied to
// all kinds of values and produce an incorrect error whenever those values
// are hashes or arrays (including arrays of tables).
// encoding.TextUnmarshaler interface but also corresponds to a TOML hash or
// array. In particular, the unmarshaler should only be applied to primitive
// TOML values. But at this point, it will be applied to all kinds of values
// and produce an incorrect error whenever those values are hashes or arrays
// (including arrays of tables).

k := rv.Kind()

Expand Down
6 changes: 3 additions & 3 deletions decode_go116.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
)

// DecodeFS is just like Decode, except it will automatically read the contents
// of the file at `fpath` from a fs.FS instance.
func DecodeFS(fsys fs.FS, fpath string, v interface{}) (MetaData, error) {
fp, err := fsys.Open(fpath)
// of the file at `path` from a fs.FS instance.
func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) {
fp, err := fsys.Open(path)
if err != nil {
return MetaData{}, err
}
Expand Down
27 changes: 13 additions & 14 deletions decode_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package toml

import "strings"

// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
// MetaData allows access to meta information about TOML data that may not be
// inferable via reflection. In particular, whether a key has been defined and
// the TOML type of a key.
type MetaData struct {
mapping map[string]interface{}
types map[string]tomlType
Expand All @@ -13,10 +13,11 @@ type MetaData struct {
context Key // Used only during decoding.
}

// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
// IsDefined reports if the key exists in the TOML data.
//
// The key should be specified hierarchically, for example to access the TOML
// key "a.b.c" you would use:
//
// // access the TOML key 'a.b.c'
// IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
Expand Down Expand Up @@ -51,13 +52,11 @@ func (md *MetaData) Type(key ...string) string {
return ""
}

// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
// Key represents any TOML key, including key groups. Use (MetaData).Keys to get
// values of this type.
type Key []string

func (k Key) String() string {
return strings.Join(k, ".")
}
func (k Key) String() string { return strings.Join(k, ".") }

func (k Key) maybeQuotedAll() string {
var ss []string
Expand Down Expand Up @@ -92,10 +91,10 @@ func (k Key) add(piece string) Key {
}

// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific. The list will have the same
// order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md *MetaData) Keys() []Key {
Expand Down
8 changes: 4 additions & 4 deletions doc.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*
Package toml implements decoding and encoding of TOML files.
This pakcage supports TOML v1.0.0, as listed on https://toml.io
This package supports TOML v1.0.0, as listed on https://toml.io
There is also support for delaying decoding with the Primitive type, and
querying the set of keys in a TOML document with the MetaData type.
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
whether a file is a valid TOML document. It can also be used to print the type
of each key in a TOML document.
The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
and can be used to verify if TOML document is valid. It can also be used to
print the type of each key.
*/
package toml
57 changes: 26 additions & 31 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,54 +62,49 @@ var quotedReplacer = strings.NewReplacer(
"\x7f", `\u007f`,
)

// Encoder controls the encoding of Go values to a TOML document to some
// io.Writer.
// Encoder encodes a Go to a TOML document.
//
// The indentation level can be controlled with the Indent field.
// The mapping between Go values and TOML values should be precisely the same as
// for the Decode* functions. Similarly, the TextMarshaler interface is
// supported by encoding the resulting bytes as strings. If you want to write
// arbitrary binary data then you will need to use something like base64 since
// TOML does not have any binary types.
//
// When encoding TOML hashes (Go maps or structs), keys without any sub-hashes
// are encoded first.
//
// Go maps will be sorted alphabetically by key for deterministic output.
//
// Encoding Go values without a corresponding TOML representation will return an
// error. Examples of this includes maps with non-string keys, slices with nil
// elements, embedded non-struct types, and nested slices containing maps or
// structs. (e.g. [][]map[string]string is not allowed but []map[string]string
// is okay, as is []map[string][]string).
//
// NOTE: Only exported keys are encoded due to the use of reflection. Unexported
// keys are silently discarded.
type Encoder struct {
// A single indentation level. By default it is two spaces.
// The string to use for a single indentation level. The default is two
// spaces.
Indent string

// hasWritten is whether we have written any output to w yet.
hasWritten bool
w *bufio.Writer
}

// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
// given. By default, a single indentation level is 2 spaces.
// NewEncoder create a new Encoder.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: bufio.NewWriter(w),
Indent: " ",
}
}

// Encode writes a TOML representation of the Go value to the underlying
// io.Writer. If the value given cannot be encoded to a valid TOML document,
// then an error is returned.
//
// The mapping between Go values and TOML values should be precisely the same
// as for the Decode* functions. Similarly, the TextMarshaler interface is
// supported by encoding the resulting bytes as strings. (If you want to write
// arbitrary binary data then you will need to use something like base64 since
// TOML does not have any binary types.)
//
// When encoding TOML hashes (i.e., Go maps or structs), keys without any
// sub-hashes are encoded first.
//
// If a Go map is encoded, then its keys are sorted alphabetically for
// deterministic output. More control over this behavior may be provided if
// there is demand for it.
//
// Encoding Go values without a corresponding TOML representation---like map
// types with non-string keys---will cause an error to be returned. Similarly
// for mixed arrays/slices, arrays/slices with nil elements, embedded
// non-struct types and nested slices containing maps or structs.
// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
// and so is []map[string][]string.)
// Encode writes a TOML representation of the Go value to the Encoder's writer.
//
// Beware: due to the use of reflection, only exported keys are encoded. Non
// exported keys are silently discarded.
// An error is returned if the value given cannot be encoded to a valid TOML
// document.
func (enc *Encoder) Encode(v interface{}) error {
rv := eindirect(reflect.ValueOf(v))
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
Expand Down
1 change: 0 additions & 1 deletion fuzz_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// +build gofuzzbeta
// +build go1.17

package toml

Expand Down
21 changes: 20 additions & 1 deletion parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,26 @@ func (p *parser) valueFloat(it item) (interface{}, tomlType) {
return num, p.typeOfPrimitive(it)
}

// Timezones used for local datetime, date, and time.
// Timezones used for local datetime, date, and time TOML types.
//
// The exact way times and dates without a timezone should be interpreted is not
// well-defined in the TOML specification and left to the implementation. These
// defaults to current local timezone offset of the computer, but this can be
// changed by changing these variables before decoding.
//
// The reason we use three different variables for this is to support
// round-tripping.
//
// TODO: these really shouldn't be package-level globals, and there also
// shouldn't be three variables. The problem is that the time is decoded in the
// parse stage, rather than the decode stage.
//
// Decoder and Encoder should both support a Timezone attribute instead.
// Round-tripping is more tricky though, as there isn't a way to pass this
// information yet.
//
// The reason they're exported is because they're referred from in e.g.
// internal/tag.
var (
localOffset = func() int { _, o := time.Now().Zone(); return o }()
LocalDatetime = time.FixedZone("datetime-local", localOffset)
Expand Down

0 comments on commit 5f40317

Please sign in to comment.