mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 00:22:26 -06:00 
			
		
		
		
	Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.0...v1.0.1) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			1121 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1121 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package toml
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"encoding"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"math"
 | 
						|
	"reflect"
 | 
						|
	"sort"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
	"unicode"
 | 
						|
 | 
						|
	"github.com/pelletier/go-toml/v2/internal/characters"
 | 
						|
)
 | 
						|
 | 
						|
// Marshal serializes a Go value as a TOML document.
 | 
						|
//
 | 
						|
// It is a shortcut for Encoder.Encode() with the default options.
 | 
						|
func Marshal(v interface{}) ([]byte, error) {
 | 
						|
	var buf bytes.Buffer
 | 
						|
	enc := NewEncoder(&buf)
 | 
						|
 | 
						|
	err := enc.Encode(v)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return buf.Bytes(), nil
 | 
						|
}
 | 
						|
 | 
						|
// Encoder writes a TOML document to an output stream.
 | 
						|
type Encoder struct {
 | 
						|
	// output
 | 
						|
	w io.Writer
 | 
						|
 | 
						|
	// global settings
 | 
						|
	tablesInline       bool
 | 
						|
	arraysMultiline    bool
 | 
						|
	indentSymbol       string
 | 
						|
	indentTables       bool
 | 
						|
	marshalJsonNumbers bool
 | 
						|
}
 | 
						|
 | 
						|
// NewEncoder returns a new Encoder that writes to w.
 | 
						|
func NewEncoder(w io.Writer) *Encoder {
 | 
						|
	return &Encoder{
 | 
						|
		w:            w,
 | 
						|
		indentSymbol: "  ",
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// SetTablesInline forces the encoder to emit all tables inline.
 | 
						|
//
 | 
						|
// This behavior can be controlled on an individual struct field basis with the
 | 
						|
// inline tag:
 | 
						|
//
 | 
						|
//	MyField `toml:",inline"`
 | 
						|
func (enc *Encoder) SetTablesInline(inline bool) *Encoder {
 | 
						|
	enc.tablesInline = inline
 | 
						|
	return enc
 | 
						|
}
 | 
						|
 | 
						|
// SetArraysMultiline forces the encoder to emit all arrays with one element per
 | 
						|
// line.
 | 
						|
//
 | 
						|
// This behavior can be controlled on an individual struct field basis with the multiline tag:
 | 
						|
//
 | 
						|
//	MyField `multiline:"true"`
 | 
						|
func (enc *Encoder) SetArraysMultiline(multiline bool) *Encoder {
 | 
						|
	enc.arraysMultiline = multiline
 | 
						|
	return enc
 | 
						|
}
 | 
						|
 | 
						|
// SetIndentSymbol defines the string that should be used for indentation. The
 | 
						|
// provided string is repeated for each indentation level. Defaults to two
 | 
						|
// spaces.
 | 
						|
func (enc *Encoder) SetIndentSymbol(s string) *Encoder {
 | 
						|
	enc.indentSymbol = s
 | 
						|
	return enc
 | 
						|
}
 | 
						|
 | 
						|
// SetIndentTables forces the encoder to intent tables and array tables.
 | 
						|
func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
 | 
						|
	enc.indentTables = indent
 | 
						|
	return enc
 | 
						|
}
 | 
						|
 | 
						|
// SetMarshalJsonNumbers forces the encoder to serialize `json.Number` as a
 | 
						|
// float or integer instead of relying on TextMarshaler to emit a string.
 | 
						|
//
 | 
						|
// *Unstable:* This method does not follow the compatibility guarantees of
 | 
						|
// semver. It can be changed or removed without a new major version being
 | 
						|
// issued.
 | 
						|
func (enc *Encoder) SetMarshalJsonNumbers(indent bool) *Encoder {
 | 
						|
	enc.marshalJsonNumbers = indent
 | 
						|
	return enc
 | 
						|
}
 | 
						|
 | 
						|
// Encode writes a TOML representation of v to the stream.
 | 
						|
//
 | 
						|
// If v cannot be represented to TOML it returns an error.
 | 
						|
//
 | 
						|
// # Encoding rules
 | 
						|
//
 | 
						|
// A top level slice containing only maps or structs is encoded as [[table
 | 
						|
// array]].
 | 
						|
//
 | 
						|
// All slices not matching rule 1 are encoded as [array]. As a result, any map
 | 
						|
// or struct they contain is encoded as an {inline table}.
 | 
						|
//
 | 
						|
// Nil interfaces and nil pointers are not supported.
 | 
						|
//
 | 
						|
// Keys in key-values always have one part.
 | 
						|
//
 | 
						|
// Intermediate tables are always printed.
 | 
						|
//
 | 
						|
// By default, strings are encoded as literal string, unless they contain either
 | 
						|
// a newline character or a single quote. In that case they are emitted as
 | 
						|
// quoted strings.
 | 
						|
//
 | 
						|
// Unsigned integers larger than math.MaxInt64 cannot be encoded. Doing so
 | 
						|
// results in an error. This rule exists because the TOML specification only
 | 
						|
// requires parsers to support at least the 64 bits integer range. Allowing
 | 
						|
// larger numbers would create non-standard TOML documents, which may not be
 | 
						|
// readable (at best) by other implementations. To encode such numbers, a
 | 
						|
// solution is a custom type that implements encoding.TextMarshaler.
 | 
						|
//
 | 
						|
// When encoding structs, fields are encoded in order of definition, with their
 | 
						|
// exact name.
 | 
						|
//
 | 
						|
// Tables and array tables are separated by empty lines. However, consecutive
 | 
						|
// subtables definitions are not. For example:
 | 
						|
//
 | 
						|
//	[top1]
 | 
						|
//
 | 
						|
//	[top2]
 | 
						|
//	[top2.child1]
 | 
						|
//
 | 
						|
//	[[array]]
 | 
						|
//
 | 
						|
//	[[array]]
 | 
						|
//	[array.child2]
 | 
						|
//
 | 
						|
// # Struct tags
 | 
						|
//
 | 
						|
// The encoding of each public struct field can be customized by the format
 | 
						|
// string in the "toml" key of the struct field's tag. This follows
 | 
						|
// encoding/json's convention. The format string starts with the name of the
 | 
						|
// field, optionally followed by a comma-separated list of options. The name may
 | 
						|
// be empty in order to provide options without overriding the default name.
 | 
						|
//
 | 
						|
// The "multiline" option emits strings as quoted multi-line TOML strings. It
 | 
						|
// has no effect on fields that would not be encoded as strings.
 | 
						|
//
 | 
						|
// The "inline" option turns fields that would be emitted as tables into inline
 | 
						|
// tables instead. It has no effect on other fields.
 | 
						|
//
 | 
						|
// The "omitempty" option prevents empty values or groups from being emitted.
 | 
						|
//
 | 
						|
// The "commented" option prefixes the value and all its children with a comment
 | 
						|
// symbol.
 | 
						|
//
 | 
						|
// In addition to the "toml" tag struct tag, a "comment" tag can be used to emit
 | 
						|
// a TOML comment before the value being annotated. Comments are ignored inside
 | 
						|
// inline tables. For array tables, the comment is only present before the first
 | 
						|
// element of the array.
 | 
						|
func (enc *Encoder) Encode(v interface{}) error {
 | 
						|
	var (
 | 
						|
		b   []byte
 | 
						|
		ctx encoderCtx
 | 
						|
	)
 | 
						|
 | 
						|
	ctx.inline = enc.tablesInline
 | 
						|
 | 
						|
	if v == nil {
 | 
						|
		return fmt.Errorf("toml: cannot encode a nil interface")
 | 
						|
	}
 | 
						|
 | 
						|
	b, err := enc.encode(b, ctx, reflect.ValueOf(v))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = enc.w.Write(b)
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("toml: cannot write: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
type valueOptions struct {
 | 
						|
	multiline bool
 | 
						|
	omitempty bool
 | 
						|
	commented bool
 | 
						|
	comment   string
 | 
						|
}
 | 
						|
 | 
						|
type encoderCtx struct {
 | 
						|
	// Current top-level key.
 | 
						|
	parentKey []string
 | 
						|
 | 
						|
	// Key that should be used for a KV.
 | 
						|
	key string
 | 
						|
	// Extra flag to account for the empty string
 | 
						|
	hasKey bool
 | 
						|
 | 
						|
	// Set to true to indicate that the encoder is inside a KV, so that all
 | 
						|
	// tables need to be inlined.
 | 
						|
	insideKv bool
 | 
						|
 | 
						|
	// Set to true to skip the first table header in an array table.
 | 
						|
	skipTableHeader bool
 | 
						|
 | 
						|
	// Should the next table be encoded as inline
 | 
						|
	inline bool
 | 
						|
 | 
						|
	// Indentation level
 | 
						|
	indent int
 | 
						|
 | 
						|
	// Prefix the current value with a comment.
 | 
						|
	commented bool
 | 
						|
 | 
						|
	// Options coming from struct tags
 | 
						|
	options valueOptions
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *encoderCtx) shiftKey() {
 | 
						|
	if ctx.hasKey {
 | 
						|
		ctx.parentKey = append(ctx.parentKey, ctx.key)
 | 
						|
		ctx.clearKey()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *encoderCtx) setKey(k string) {
 | 
						|
	ctx.key = k
 | 
						|
	ctx.hasKey = true
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *encoderCtx) clearKey() {
 | 
						|
	ctx.key = ""
 | 
						|
	ctx.hasKey = false
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *encoderCtx) isRoot() bool {
 | 
						|
	return len(ctx.parentKey) == 0 && !ctx.hasKey
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	i := v.Interface()
 | 
						|
 | 
						|
	switch x := i.(type) {
 | 
						|
	case time.Time:
 | 
						|
		if x.Nanosecond() > 0 {
 | 
						|
			return x.AppendFormat(b, time.RFC3339Nano), nil
 | 
						|
		}
 | 
						|
		return x.AppendFormat(b, time.RFC3339), nil
 | 
						|
	case LocalTime:
 | 
						|
		return append(b, x.String()...), nil
 | 
						|
	case LocalDate:
 | 
						|
		return append(b, x.String()...), nil
 | 
						|
	case LocalDateTime:
 | 
						|
		return append(b, x.String()...), nil
 | 
						|
	case json.Number:
 | 
						|
		if enc.marshalJsonNumbers {
 | 
						|
			if x == "" { /// Useful zero value.
 | 
						|
				return append(b, "0"...), nil
 | 
						|
			} else if v, err := x.Int64(); err == nil {
 | 
						|
				return enc.encode(b, ctx, reflect.ValueOf(v))
 | 
						|
			} else if f, err := x.Float64(); err == nil {
 | 
						|
				return enc.encode(b, ctx, reflect.ValueOf(f))
 | 
						|
			} else {
 | 
						|
				return nil, fmt.Errorf("toml: unable to convert %q to int64 or float64", x)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	hasTextMarshaler := v.Type().Implements(textMarshalerType)
 | 
						|
	if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
 | 
						|
		if !hasTextMarshaler {
 | 
						|
			v = v.Addr()
 | 
						|
		}
 | 
						|
 | 
						|
		if ctx.isRoot() {
 | 
						|
			return nil, fmt.Errorf("toml: type %s implementing the TextMarshaler interface cannot be a root element", v.Type())
 | 
						|
		}
 | 
						|
 | 
						|
		text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		b = enc.encodeString(b, string(text), ctx.options)
 | 
						|
 | 
						|
		return b, nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch v.Kind() {
 | 
						|
	// containers
 | 
						|
	case reflect.Map:
 | 
						|
		return enc.encodeMap(b, ctx, v)
 | 
						|
	case reflect.Struct:
 | 
						|
		return enc.encodeStruct(b, ctx, v)
 | 
						|
	case reflect.Slice, reflect.Array:
 | 
						|
		return enc.encodeSlice(b, ctx, v)
 | 
						|
	case reflect.Interface:
 | 
						|
		if v.IsNil() {
 | 
						|
			return nil, fmt.Errorf("toml: encoding a nil interface is not supported")
 | 
						|
		}
 | 
						|
 | 
						|
		return enc.encode(b, ctx, v.Elem())
 | 
						|
	case reflect.Ptr:
 | 
						|
		if v.IsNil() {
 | 
						|
			return enc.encode(b, ctx, reflect.Zero(v.Type().Elem()))
 | 
						|
		}
 | 
						|
 | 
						|
		return enc.encode(b, ctx, v.Elem())
 | 
						|
 | 
						|
	// values
 | 
						|
	case reflect.String:
 | 
						|
		b = enc.encodeString(b, v.String(), ctx.options)
 | 
						|
	case reflect.Float32:
 | 
						|
		f := v.Float()
 | 
						|
 | 
						|
		if math.IsNaN(f) {
 | 
						|
			b = append(b, "nan"...)
 | 
						|
		} else if f > math.MaxFloat32 {
 | 
						|
			b = append(b, "inf"...)
 | 
						|
		} else if f < -math.MaxFloat32 {
 | 
						|
			b = append(b, "-inf"...)
 | 
						|
		} else if math.Trunc(f) == f {
 | 
						|
			b = strconv.AppendFloat(b, f, 'f', 1, 32)
 | 
						|
		} else {
 | 
						|
			b = strconv.AppendFloat(b, f, 'f', -1, 32)
 | 
						|
		}
 | 
						|
	case reflect.Float64:
 | 
						|
		f := v.Float()
 | 
						|
		if math.IsNaN(f) {
 | 
						|
			b = append(b, "nan"...)
 | 
						|
		} else if f > math.MaxFloat64 {
 | 
						|
			b = append(b, "inf"...)
 | 
						|
		} else if f < -math.MaxFloat64 {
 | 
						|
			b = append(b, "-inf"...)
 | 
						|
		} else if math.Trunc(f) == f {
 | 
						|
			b = strconv.AppendFloat(b, f, 'f', 1, 64)
 | 
						|
		} else {
 | 
						|
			b = strconv.AppendFloat(b, f, 'f', -1, 64)
 | 
						|
		}
 | 
						|
	case reflect.Bool:
 | 
						|
		if v.Bool() {
 | 
						|
			b = append(b, "true"...)
 | 
						|
		} else {
 | 
						|
			b = append(b, "false"...)
 | 
						|
		}
 | 
						|
	case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
 | 
						|
		x := v.Uint()
 | 
						|
		if x > uint64(math.MaxInt64) {
 | 
						|
			return nil, fmt.Errorf("toml: not encoding uint (%d) greater than max int64 (%d)", x, int64(math.MaxInt64))
 | 
						|
		}
 | 
						|
		b = strconv.AppendUint(b, x, 10)
 | 
						|
	case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
 | 
						|
		b = strconv.AppendInt(b, v.Int(), 10)
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("toml: cannot encode value of type %s", v.Kind())
 | 
						|
	}
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func isNil(v reflect.Value) bool {
 | 
						|
	switch v.Kind() {
 | 
						|
	case reflect.Ptr, reflect.Interface, reflect.Map:
 | 
						|
		return v.IsNil()
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func shouldOmitEmpty(options valueOptions, v reflect.Value) bool {
 | 
						|
	return options.omitempty && isEmptyValue(v)
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
 | 
						|
	var err error
 | 
						|
 | 
						|
	if !ctx.inline {
 | 
						|
		b = enc.encodeComment(ctx.indent, options.comment, b)
 | 
						|
		b = enc.commented(ctx.commented, b)
 | 
						|
		b = enc.indent(ctx.indent, b)
 | 
						|
	}
 | 
						|
 | 
						|
	b = enc.encodeKey(b, ctx.key)
 | 
						|
	b = append(b, " = "...)
 | 
						|
 | 
						|
	// create a copy of the context because the value of a KV shouldn't
 | 
						|
	// modify the global context.
 | 
						|
	subctx := ctx
 | 
						|
	subctx.insideKv = true
 | 
						|
	subctx.shiftKey()
 | 
						|
	subctx.options = options
 | 
						|
 | 
						|
	b, err = enc.encode(b, subctx, v)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) commented(commented bool, b []byte) []byte {
 | 
						|
	if commented {
 | 
						|
		return append(b, "# "...)
 | 
						|
	}
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
func isEmptyValue(v reflect.Value) bool {
 | 
						|
	switch v.Kind() {
 | 
						|
	case reflect.Struct:
 | 
						|
		return isEmptyStruct(v)
 | 
						|
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
 | 
						|
		return v.Len() == 0
 | 
						|
	case reflect.Bool:
 | 
						|
		return !v.Bool()
 | 
						|
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
		return v.Int() == 0
 | 
						|
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 | 
						|
		return v.Uint() == 0
 | 
						|
	case reflect.Float32, reflect.Float64:
 | 
						|
		return v.Float() == 0
 | 
						|
	case reflect.Interface, reflect.Ptr:
 | 
						|
		return v.IsNil()
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func isEmptyStruct(v reflect.Value) bool {
 | 
						|
	// TODO: merge with walkStruct and cache.
 | 
						|
	typ := v.Type()
 | 
						|
	for i := 0; i < typ.NumField(); i++ {
 | 
						|
		fieldType := typ.Field(i)
 | 
						|
 | 
						|
		// only consider exported fields
 | 
						|
		if fieldType.PkgPath != "" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		tag := fieldType.Tag.Get("toml")
 | 
						|
 | 
						|
		// special field name to skip field
 | 
						|
		if tag == "-" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		f := v.Field(i)
 | 
						|
 | 
						|
		if !isEmptyValue(f) {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
const literalQuote = '\''
 | 
						|
 | 
						|
func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byte {
 | 
						|
	if needsQuoting(v) {
 | 
						|
		return enc.encodeQuotedString(options.multiline, b, v)
 | 
						|
	}
 | 
						|
 | 
						|
	return enc.encodeLiteralString(b, v)
 | 
						|
}
 | 
						|
 | 
						|
func needsQuoting(v string) bool {
 | 
						|
	// TODO: vectorize
 | 
						|
	for _, b := range []byte(v) {
 | 
						|
		if b == '\'' || b == '\r' || b == '\n' || characters.InvalidAscii(b) {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// caller should have checked that the string does not contain new lines or ' .
 | 
						|
func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
 | 
						|
	b = append(b, literalQuote)
 | 
						|
	b = append(b, v...)
 | 
						|
	b = append(b, literalQuote)
 | 
						|
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byte {
 | 
						|
	stringQuote := `"`
 | 
						|
 | 
						|
	if multiline {
 | 
						|
		stringQuote = `"""`
 | 
						|
	}
 | 
						|
 | 
						|
	b = append(b, stringQuote...)
 | 
						|
	if multiline {
 | 
						|
		b = append(b, '\n')
 | 
						|
	}
 | 
						|
 | 
						|
	const (
 | 
						|
		hextable = "0123456789ABCDEF"
 | 
						|
		// U+0000 to U+0008, U+000A to U+001F, U+007F
 | 
						|
		nul = 0x0
 | 
						|
		bs  = 0x8
 | 
						|
		lf  = 0xa
 | 
						|
		us  = 0x1f
 | 
						|
		del = 0x7f
 | 
						|
	)
 | 
						|
 | 
						|
	for _, r := range []byte(v) {
 | 
						|
		switch r {
 | 
						|
		case '\\':
 | 
						|
			b = append(b, `\\`...)
 | 
						|
		case '"':
 | 
						|
			b = append(b, `\"`...)
 | 
						|
		case '\b':
 | 
						|
			b = append(b, `\b`...)
 | 
						|
		case '\f':
 | 
						|
			b = append(b, `\f`...)
 | 
						|
		case '\n':
 | 
						|
			if multiline {
 | 
						|
				b = append(b, r)
 | 
						|
			} else {
 | 
						|
				b = append(b, `\n`...)
 | 
						|
			}
 | 
						|
		case '\r':
 | 
						|
			b = append(b, `\r`...)
 | 
						|
		case '\t':
 | 
						|
			b = append(b, `\t`...)
 | 
						|
		default:
 | 
						|
			switch {
 | 
						|
			case r >= nul && r <= bs, r >= lf && r <= us, r == del:
 | 
						|
				b = append(b, `\u00`...)
 | 
						|
				b = append(b, hextable[r>>4])
 | 
						|
				b = append(b, hextable[r&0x0f])
 | 
						|
			default:
 | 
						|
				b = append(b, r)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	b = append(b, stringQuote...)
 | 
						|
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
// caller should have checked that the string is in A-Z / a-z / 0-9 / - / _ .
 | 
						|
func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
 | 
						|
	return append(b, v...)
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
 | 
						|
	if len(ctx.parentKey) == 0 {
 | 
						|
		return b, nil
 | 
						|
	}
 | 
						|
 | 
						|
	b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
 | 
						|
 | 
						|
	b = enc.commented(ctx.commented, b)
 | 
						|
 | 
						|
	b = enc.indent(ctx.indent, b)
 | 
						|
 | 
						|
	b = append(b, '[')
 | 
						|
 | 
						|
	b = enc.encodeKey(b, ctx.parentKey[0])
 | 
						|
 | 
						|
	for _, k := range ctx.parentKey[1:] {
 | 
						|
		b = append(b, '.')
 | 
						|
		b = enc.encodeKey(b, k)
 | 
						|
	}
 | 
						|
 | 
						|
	b = append(b, "]\n"...)
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
//nolint:cyclop
 | 
						|
func (enc *Encoder) encodeKey(b []byte, k string) []byte {
 | 
						|
	needsQuotation := false
 | 
						|
	cannotUseLiteral := false
 | 
						|
 | 
						|
	if len(k) == 0 {
 | 
						|
		return append(b, "''"...)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, c := range k {
 | 
						|
		if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if c == literalQuote {
 | 
						|
			cannotUseLiteral = true
 | 
						|
		}
 | 
						|
 | 
						|
		needsQuotation = true
 | 
						|
	}
 | 
						|
 | 
						|
	if needsQuotation && needsQuoting(k) {
 | 
						|
		cannotUseLiteral = true
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case cannotUseLiteral:
 | 
						|
		return enc.encodeQuotedString(false, b, k)
 | 
						|
	case needsQuotation:
 | 
						|
		return enc.encodeLiteralString(b, k)
 | 
						|
	default:
 | 
						|
		return enc.encodeUnquotedKey(b, k)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) keyToString(k reflect.Value) (string, error) {
 | 
						|
	keyType := k.Type()
 | 
						|
	switch {
 | 
						|
	case keyType.Kind() == reflect.String:
 | 
						|
		return k.String(), nil
 | 
						|
 | 
						|
	case keyType.Implements(textMarshalerType):
 | 
						|
		keyB, err := k.Interface().(encoding.TextMarshaler).MarshalText()
 | 
						|
		if err != nil {
 | 
						|
			return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err)
 | 
						|
		}
 | 
						|
		return string(keyB), nil
 | 
						|
	}
 | 
						|
	return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	var (
 | 
						|
		t                 table
 | 
						|
		emptyValueOptions valueOptions
 | 
						|
	)
 | 
						|
 | 
						|
	iter := v.MapRange()
 | 
						|
	for iter.Next() {
 | 
						|
		v := iter.Value()
 | 
						|
 | 
						|
		if isNil(v) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		k, err := enc.keyToString(iter.Key())
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if willConvertToTableOrArrayTable(ctx, v) {
 | 
						|
			t.pushTable(k, v, emptyValueOptions)
 | 
						|
		} else {
 | 
						|
			t.pushKV(k, v, emptyValueOptions)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	sortEntriesByKey(t.kvs)
 | 
						|
	sortEntriesByKey(t.tables)
 | 
						|
 | 
						|
	return enc.encodeTable(b, ctx, t)
 | 
						|
}
 | 
						|
 | 
						|
func sortEntriesByKey(e []entry) {
 | 
						|
	sort.Slice(e, func(i, j int) bool {
 | 
						|
		return e[i].Key < e[j].Key
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
type entry struct {
 | 
						|
	Key     string
 | 
						|
	Value   reflect.Value
 | 
						|
	Options valueOptions
 | 
						|
}
 | 
						|
 | 
						|
type table struct {
 | 
						|
	kvs    []entry
 | 
						|
	tables []entry
 | 
						|
}
 | 
						|
 | 
						|
func (t *table) pushKV(k string, v reflect.Value, options valueOptions) {
 | 
						|
	for _, e := range t.kvs {
 | 
						|
		if e.Key == k {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	t.kvs = append(t.kvs, entry{Key: k, Value: v, Options: options})
 | 
						|
}
 | 
						|
 | 
						|
func (t *table) pushTable(k string, v reflect.Value, options valueOptions) {
 | 
						|
	for _, e := range t.tables {
 | 
						|
		if e.Key == k {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
	t.tables = append(t.tables, entry{Key: k, Value: v, Options: options})
 | 
						|
}
 | 
						|
 | 
						|
func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
 | 
						|
	// TODO: cache this
 | 
						|
	typ := v.Type()
 | 
						|
	for i := 0; i < typ.NumField(); i++ {
 | 
						|
		fieldType := typ.Field(i)
 | 
						|
 | 
						|
		// only consider exported fields
 | 
						|
		if fieldType.PkgPath != "" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		tag := fieldType.Tag.Get("toml")
 | 
						|
 | 
						|
		// special field name to skip field
 | 
						|
		if tag == "-" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		k, opts := parseTag(tag)
 | 
						|
		if !isValidName(k) {
 | 
						|
			k = ""
 | 
						|
		}
 | 
						|
 | 
						|
		f := v.Field(i)
 | 
						|
 | 
						|
		if k == "" {
 | 
						|
			if fieldType.Anonymous {
 | 
						|
				if fieldType.Type.Kind() == reflect.Struct {
 | 
						|
					walkStruct(ctx, t, f)
 | 
						|
				} else if fieldType.Type.Kind() == reflect.Pointer && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
 | 
						|
					walkStruct(ctx, t, f.Elem())
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			} else {
 | 
						|
				k = fieldType.Name
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if isNil(f) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		options := valueOptions{
 | 
						|
			multiline: opts.multiline,
 | 
						|
			omitempty: opts.omitempty,
 | 
						|
			commented: opts.commented,
 | 
						|
			comment:   fieldType.Tag.Get("comment"),
 | 
						|
		}
 | 
						|
 | 
						|
		if opts.inline || !willConvertToTableOrArrayTable(ctx, f) {
 | 
						|
			t.pushKV(k, f, options)
 | 
						|
		} else {
 | 
						|
			t.pushTable(k, f, options)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeStruct(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	var t table
 | 
						|
 | 
						|
	walkStruct(ctx, &t, v)
 | 
						|
 | 
						|
	return enc.encodeTable(b, ctx, t)
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeComment(indent int, comment string, b []byte) []byte {
 | 
						|
	for len(comment) > 0 {
 | 
						|
		var line string
 | 
						|
		idx := strings.IndexByte(comment, '\n')
 | 
						|
		if idx >= 0 {
 | 
						|
			line = comment[:idx]
 | 
						|
			comment = comment[idx+1:]
 | 
						|
		} else {
 | 
						|
			line = comment
 | 
						|
			comment = ""
 | 
						|
		}
 | 
						|
		b = enc.indent(indent, b)
 | 
						|
		b = append(b, "# "...)
 | 
						|
		b = append(b, line...)
 | 
						|
		b = append(b, '\n')
 | 
						|
	}
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
func isValidName(s string) bool {
 | 
						|
	if s == "" {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	for _, c := range s {
 | 
						|
		switch {
 | 
						|
		case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
 | 
						|
			// Backslash and quote chars are reserved, but
 | 
						|
			// otherwise any punctuation chars are allowed
 | 
						|
			// in a tag name.
 | 
						|
		case !unicode.IsLetter(c) && !unicode.IsDigit(c):
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
type tagOptions struct {
 | 
						|
	multiline bool
 | 
						|
	inline    bool
 | 
						|
	omitempty bool
 | 
						|
	commented bool
 | 
						|
}
 | 
						|
 | 
						|
func parseTag(tag string) (string, tagOptions) {
 | 
						|
	opts := tagOptions{}
 | 
						|
 | 
						|
	idx := strings.Index(tag, ",")
 | 
						|
	if idx == -1 {
 | 
						|
		return tag, opts
 | 
						|
	}
 | 
						|
 | 
						|
	raw := tag[idx+1:]
 | 
						|
	tag = string(tag[:idx])
 | 
						|
	for raw != "" {
 | 
						|
		var o string
 | 
						|
		i := strings.Index(raw, ",")
 | 
						|
		if i >= 0 {
 | 
						|
			o, raw = raw[:i], raw[i+1:]
 | 
						|
		} else {
 | 
						|
			o, raw = raw, ""
 | 
						|
		}
 | 
						|
		switch o {
 | 
						|
		case "multiline":
 | 
						|
			opts.multiline = true
 | 
						|
		case "inline":
 | 
						|
			opts.inline = true
 | 
						|
		case "omitempty":
 | 
						|
			opts.omitempty = true
 | 
						|
		case "commented":
 | 
						|
			opts.commented = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return tag, opts
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
 | 
						|
	var err error
 | 
						|
 | 
						|
	ctx.shiftKey()
 | 
						|
 | 
						|
	if ctx.insideKv || (ctx.inline && !ctx.isRoot()) {
 | 
						|
		return enc.encodeTableInline(b, ctx, t)
 | 
						|
	}
 | 
						|
 | 
						|
	if !ctx.skipTableHeader {
 | 
						|
		b, err = enc.encodeTableHeader(ctx, b)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if enc.indentTables && len(ctx.parentKey) > 0 {
 | 
						|
			ctx.indent++
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ctx.skipTableHeader = false
 | 
						|
 | 
						|
	hasNonEmptyKV := false
 | 
						|
	for _, kv := range t.kvs {
 | 
						|
		if shouldOmitEmpty(kv.Options, kv.Value) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		hasNonEmptyKV = true
 | 
						|
 | 
						|
		ctx.setKey(kv.Key)
 | 
						|
		ctx2 := ctx
 | 
						|
		ctx2.commented = kv.Options.commented || ctx2.commented
 | 
						|
 | 
						|
		b, err = enc.encodeKv(b, ctx2, kv.Options, kv.Value)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		b = append(b, '\n')
 | 
						|
	}
 | 
						|
 | 
						|
	first := true
 | 
						|
	for _, table := range t.tables {
 | 
						|
		if shouldOmitEmpty(table.Options, table.Value) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if first {
 | 
						|
			first = false
 | 
						|
			if hasNonEmptyKV {
 | 
						|
				b = append(b, '\n')
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			b = append(b, "\n"...)
 | 
						|
		}
 | 
						|
 | 
						|
		ctx.setKey(table.Key)
 | 
						|
 | 
						|
		ctx.options = table.Options
 | 
						|
		ctx2 := ctx
 | 
						|
		ctx2.commented = ctx2.commented || ctx.options.commented
 | 
						|
 | 
						|
		b, err = enc.encode(b, ctx2, table.Value)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte, error) {
 | 
						|
	var err error
 | 
						|
 | 
						|
	b = append(b, '{')
 | 
						|
 | 
						|
	first := true
 | 
						|
	for _, kv := range t.kvs {
 | 
						|
		if shouldOmitEmpty(kv.Options, kv.Value) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if first {
 | 
						|
			first = false
 | 
						|
		} else {
 | 
						|
			b = append(b, `, `...)
 | 
						|
		}
 | 
						|
 | 
						|
		ctx.setKey(kv.Key)
 | 
						|
 | 
						|
		b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if len(t.tables) > 0 {
 | 
						|
		panic("inline table cannot contain nested tables, only key-values")
 | 
						|
	}
 | 
						|
 | 
						|
	b = append(b, "}"...)
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
 | 
						|
	if !v.IsValid() {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	t := v.Type()
 | 
						|
	switch t.Kind() {
 | 
						|
	case reflect.Map, reflect.Struct:
 | 
						|
		return !ctx.inline
 | 
						|
	case reflect.Interface:
 | 
						|
		return willConvertToTable(ctx, v.Elem())
 | 
						|
	case reflect.Ptr:
 | 
						|
		if v.IsNil() {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		return willConvertToTable(ctx, v.Elem())
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
 | 
						|
	if ctx.insideKv {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	t := v.Type()
 | 
						|
 | 
						|
	if t.Kind() == reflect.Interface {
 | 
						|
		return willConvertToTableOrArrayTable(ctx, v.Elem())
 | 
						|
	}
 | 
						|
 | 
						|
	if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
 | 
						|
		if v.Len() == 0 {
 | 
						|
			// An empty slice should be a kv = [].
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		for i := 0; i < v.Len(); i++ {
 | 
						|
			t := willConvertToTable(ctx, v.Index(i))
 | 
						|
 | 
						|
			if !t {
 | 
						|
				return false
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	return willConvertToTable(ctx, v)
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeSlice(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	if v.Len() == 0 {
 | 
						|
		b = append(b, "[]"...)
 | 
						|
 | 
						|
		return b, nil
 | 
						|
	}
 | 
						|
 | 
						|
	if willConvertToTableOrArrayTable(ctx, v) {
 | 
						|
		return enc.encodeSliceAsArrayTable(b, ctx, v)
 | 
						|
	}
 | 
						|
 | 
						|
	return enc.encodeSliceAsArray(b, ctx, v)
 | 
						|
}
 | 
						|
 | 
						|
// caller should have checked that v is a slice that only contains values that
 | 
						|
// encode into tables.
 | 
						|
func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	ctx.shiftKey()
 | 
						|
 | 
						|
	scratch := make([]byte, 0, 64)
 | 
						|
 | 
						|
	scratch = enc.commented(ctx.commented, scratch)
 | 
						|
 | 
						|
	if enc.indentTables {
 | 
						|
		scratch = enc.indent(ctx.indent, scratch)
 | 
						|
	}
 | 
						|
 | 
						|
	scratch = append(scratch, "[["...)
 | 
						|
 | 
						|
	for i, k := range ctx.parentKey {
 | 
						|
		if i > 0 {
 | 
						|
			scratch = append(scratch, '.')
 | 
						|
		}
 | 
						|
 | 
						|
		scratch = enc.encodeKey(scratch, k)
 | 
						|
	}
 | 
						|
 | 
						|
	scratch = append(scratch, "]]\n"...)
 | 
						|
	ctx.skipTableHeader = true
 | 
						|
 | 
						|
	b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
 | 
						|
 | 
						|
	if enc.indentTables {
 | 
						|
		ctx.indent++
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		if i != 0 {
 | 
						|
			b = append(b, "\n"...)
 | 
						|
		}
 | 
						|
 | 
						|
		b = append(b, scratch...)
 | 
						|
 | 
						|
		var err error
 | 
						|
		b, err = enc.encode(b, ctx, v.Index(i))
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) encodeSliceAsArray(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
 | 
						|
	multiline := ctx.options.multiline || enc.arraysMultiline
 | 
						|
	separator := ", "
 | 
						|
 | 
						|
	b = append(b, '[')
 | 
						|
 | 
						|
	subCtx := ctx
 | 
						|
	subCtx.options = valueOptions{}
 | 
						|
 | 
						|
	if multiline {
 | 
						|
		separator = ",\n"
 | 
						|
 | 
						|
		b = append(b, '\n')
 | 
						|
 | 
						|
		subCtx.indent++
 | 
						|
	}
 | 
						|
 | 
						|
	var err error
 | 
						|
	first := true
 | 
						|
 | 
						|
	for i := 0; i < v.Len(); i++ {
 | 
						|
		if first {
 | 
						|
			first = false
 | 
						|
		} else {
 | 
						|
			b = append(b, separator...)
 | 
						|
		}
 | 
						|
 | 
						|
		if multiline {
 | 
						|
			b = enc.indent(subCtx.indent, b)
 | 
						|
		}
 | 
						|
 | 
						|
		b, err = enc.encode(b, subCtx, v.Index(i))
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if multiline {
 | 
						|
		b = append(b, '\n')
 | 
						|
		b = enc.indent(ctx.indent, b)
 | 
						|
	}
 | 
						|
 | 
						|
	b = append(b, ']')
 | 
						|
 | 
						|
	return b, nil
 | 
						|
}
 | 
						|
 | 
						|
func (enc *Encoder) indent(level int, b []byte) []byte {
 | 
						|
	for i := 0; i < level; i++ {
 | 
						|
		b = append(b, enc.indentSymbol...)
 | 
						|
	}
 | 
						|
 | 
						|
	return b
 | 
						|
}
 |