|
|
@@ -303,7 +303,8 @@ const (
|
|
|
|
type entry struct {
|
|
|
|
type entry struct {
|
|
|
|
kind entryKind
|
|
|
|
kind entryKind
|
|
|
|
key string
|
|
|
|
key string
|
|
|
|
val any // entryScalar
|
|
|
|
val any // entryScalar, boxed
|
|
|
|
|
|
|
|
rv reflect.Value // entryScalar, the value the walk kept unboxed
|
|
|
|
doc *tomlDoc // entryTable
|
|
|
|
doc *tomlDoc // entryTable
|
|
|
|
docs []*tomlDoc
|
|
|
|
docs []*tomlDoc
|
|
|
|
|
|
|
|
|
|
|
@@ -359,6 +360,12 @@ func (d *tomlDoc) addScalar(key string, val any) {
|
|
|
|
d.entries = append(d.entries, entry{kind: entryScalar, key: key, val: val})
|
|
|
|
d.entries = append(d.entries, entry{kind: entryScalar, key: key, val: val})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// addScalarReflect adds a scalar whose value stays in its reflect cell until
|
|
|
|
|
|
|
|
// emission writes it, the path that keeps plain scalars from being boxed.
|
|
|
|
|
|
|
|
func (d *tomlDoc) addScalarReflect(key string, v reflect.Value) {
|
|
|
|
|
|
|
|
d.entries = append(d.entries, entry{kind: entryScalar, key: key, rv: v})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (d *tomlDoc) addTable(key string, sub *tomlDoc) *entry {
|
|
|
|
func (d *tomlDoc) addTable(key string, sub *tomlDoc) *entry {
|
|
|
|
e := entry{kind: entryTable, key: key, doc: sub}
|
|
|
|
e := entry{kind: entryTable, key: key, doc: sub}
|
|
|
|
d.entries = append(d.entries, e)
|
|
|
|
d.entries = append(d.entries, e)
|
|
|
@@ -712,6 +719,19 @@ func addField(doc *tomlDoc, name string, v reflect.Value, path encPath, forceInl
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
return addArrayValue(doc, name, v, path, forceInline)
|
|
|
|
return addArrayValue(doc, name, v, path, forceInline)
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
|
|
|
|
// A plain scalar stays in its reflect cell until emission, which
|
|
|
|
|
|
|
|
// writes it without the boxing Interface() would cost. The kinds the
|
|
|
|
|
|
|
|
// boxed rules rewrite (duration, Number, the date-time structs) take
|
|
|
|
|
|
|
|
// the boxed path as before.
|
|
|
|
|
|
|
|
if t := v.Type(); t != durationType && t != numberType {
|
|
|
|
|
|
|
|
switch v.Kind() {
|
|
|
|
|
|
|
|
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
|
|
|
|
|
|
|
|
reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
|
|
|
|
|
|
|
|
reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
|
|
|
|
|
|
|
|
doc.addScalarReflect(name, v)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
val, err := normaliseValue(v)
|
|
|
|
val, err := normaliseValue(v)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("interpres: %s: %w", path.key(name), err)
|
|
|
|
return fmt.Errorf("interpres: %s: %w", path.key(name), err)
|
|
|
@@ -762,10 +782,60 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, for
|
|
|
|
// names them.
|
|
|
|
// names them.
|
|
|
|
apath := path.key(name)
|
|
|
|
apath := path.key(name)
|
|
|
|
|
|
|
|
|
|
|
|
// Every element is resolved through MarshalTOML first, so an element that
|
|
|
|
// The per-element resolution runs only where the array could still take
|
|
|
|
// renders itself as a scalar, a table or a value array is classified by
|
|
|
|
// the [[header]] form: an interface element can never (its [[form]] would
|
|
|
|
// what it produces rather than by its Go kind, and its method runs once.
|
|
|
|
// re-parse as []map[string]any), and a plain scalar element can only when
|
|
|
|
elems := make([]reflect.Value, n)
|
|
|
|
// a Marshaler rewrites it into a table. Everywhere else the array is a
|
|
|
|
|
|
|
|
// value array and the elements are written straight from the slice.
|
|
|
|
|
|
|
|
elem := v.Type().Elem()
|
|
|
|
|
|
|
|
maybeTables := true
|
|
|
|
|
|
|
|
if elem.Kind() == reflect.Interface {
|
|
|
|
|
|
|
|
maybeTables = false
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
switch elem.Kind() {
|
|
|
|
|
|
|
|
case reflect.Struct, reflect.Map, reflect.Pointer:
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
f := encTypeFlags(elem)
|
|
|
|
|
|
|
|
if f&encFlagMarshaler == 0 && f&encFlagAddrMarshaler == 0 {
|
|
|
|
|
|
|
|
maybeTables = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// A typed array of plain scalars takes the direct emission path: no
|
|
|
|
|
|
|
|
// per-element slice, no boxing, and no error the boxed rules could raise.
|
|
|
|
|
|
|
|
// Everything wider, []any first among it, keeps the boxed path, because
|
|
|
|
|
|
|
|
// its element errors carry the element's path.
|
|
|
|
|
|
|
|
directValueArray := false
|
|
|
|
|
|
|
|
switch elem.Kind() {
|
|
|
|
|
|
|
|
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
|
|
|
|
|
|
|
|
reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64:
|
|
|
|
|
|
|
|
f := encTypeFlags(elem)
|
|
|
|
|
|
|
|
if elem != durationType && elem != numberType &&
|
|
|
|
|
|
|
|
f&(encFlagMarshaler|encFlagAddrMarshaler|encFlagTextMarshaler|encFlagAddrTextMarshaler) == 0 {
|
|
|
|
|
|
|
|
directValueArray = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
|
|
|
|
f := encTypeFlags(elem)
|
|
|
|
|
|
|
|
if f&(encFlagMarshaler|encFlagAddrMarshaler|encFlagTextMarshaler|encFlagAddrTextMarshaler) == 0 {
|
|
|
|
|
|
|
|
directValueArray = true
|
|
|
|
|
|
|
|
// The one error the boxed path raises for these is the int64
|
|
|
|
|
|
|
|
// overflow, checked here so the direct path keeps the contract.
|
|
|
|
|
|
|
|
for i := range n {
|
|
|
|
|
|
|
|
if u := v.Index(i).Uint(); u > math.MaxInt64 {
|
|
|
|
|
|
|
|
return &EncodeError{Path: apath.elem(i).segments(), Err: fmt.Errorf("unsigned value %d overflows int64", u)}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var elems []reflect.Value
|
|
|
|
|
|
|
|
if maybeTables {
|
|
|
|
|
|
|
|
// Every element is resolved through MarshalTOML first, so an element
|
|
|
|
|
|
|
|
// that renders itself as a scalar, a table or a value array is
|
|
|
|
|
|
|
|
// classified by what it produces rather than by its Go kind, and its
|
|
|
|
|
|
|
|
// method runs once.
|
|
|
|
|
|
|
|
elems = make([]reflect.Value, n)
|
|
|
|
for i := range n {
|
|
|
|
for i := range n {
|
|
|
|
if i%ctxCheckInterval == 0 {
|
|
|
|
if i%ctxCheckInterval == 0 {
|
|
|
|
if err := doc.checkCtx(); err != nil {
|
|
|
|
if err := doc.checkCtx(); err != nil {
|
|
|
@@ -778,11 +848,13 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, for
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elems[i] = ev
|
|
|
|
elems[i] = ev
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// An array keeps the [[header]] form only when every element is a table.
|
|
|
|
// An array keeps the [[header]] form only when every element is a table.
|
|
|
|
// TOML lets one array mix tables with scalars, and that mix renders as a
|
|
|
|
// TOML lets one array mix tables with scalars, and that mix renders as a
|
|
|
|
// value array with the table elements written inline.
|
|
|
|
// value array with the table elements written inline.
|
|
|
|
allTables := true
|
|
|
|
allTables := maybeTables
|
|
|
|
|
|
|
|
if allTables {
|
|
|
|
for _, ev := range elems {
|
|
|
|
for _, ev := range elems {
|
|
|
|
if !ev.IsValid() || !isTableElementValue(ev) {
|
|
|
|
if !ev.IsValid() || !isTableElementValue(ev) {
|
|
|
|
allTables = false
|
|
|
|
allTables = false
|
|
|
@@ -796,6 +868,7 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, for
|
|
|
|
if v.Type().Elem().Kind() == reflect.Interface {
|
|
|
|
if v.Type().Elem().Kind() == reflect.Interface {
|
|
|
|
allTables = false
|
|
|
|
allTables = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// A `,inline` tag on an array of tables asks for a form that would change
|
|
|
|
// A `,inline` tag on an array of tables asks for a form that would change
|
|
|
|
// the value's Go type on re-parse, so the error is the honest answer.
|
|
|
|
// the value's Go type on re-parse, so the error is the honest answer.
|
|
|
|
if forceInline && allTables {
|
|
|
|
if forceInline && allTables {
|
|
|
@@ -839,15 +912,24 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, for
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if directValueArray {
|
|
|
|
|
|
|
|
doc.addScalarReflect(name, v)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Value array. Table elements normalise to map[string]any and the emitter
|
|
|
|
// Value array. Table elements normalise to map[string]any and the emitter
|
|
|
|
// writes them as inline tables.
|
|
|
|
// writes them as inline tables.
|
|
|
|
items := make([]any, n)
|
|
|
|
items := make([]any, n)
|
|
|
|
for i, ev := range elems {
|
|
|
|
for i := range n {
|
|
|
|
if i%ctxCheckInterval == 0 {
|
|
|
|
if i%ctxCheckInterval == 0 {
|
|
|
|
if err := doc.checkCtx(); err != nil {
|
|
|
|
if err := doc.checkCtx(); err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ev := v.Index(i)
|
|
|
|
|
|
|
|
if elems != nil {
|
|
|
|
|
|
|
|
ev = elems[i]
|
|
|
|
|
|
|
|
}
|
|
|
|
val, err := normaliseValue(ev)
|
|
|
|
val, err := normaliseValue(ev)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return &EncodeError{Path: apath.elem(i).segments(), Err: err}
|
|
|
|
return &EncodeError{Path: apath.elem(i).segments(), Err: err}
|
|
|
@@ -858,6 +940,149 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, for
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeArrayValue writes a value array from its reflect value, its elements
|
|
|
|
|
|
|
|
// written one by one, each falling back to the boxed path only where the
|
|
|
|
|
|
|
|
// boxed rules rewrite it.
|
|
|
|
|
|
|
|
func (e *encoder) writeArrayValue(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
if atDepthLimit(depth) {
|
|
|
|
|
|
|
|
return errDepthLimit()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteByte('[')
|
|
|
|
|
|
|
|
for i := range v.Len() {
|
|
|
|
|
|
|
|
if i > 0 {
|
|
|
|
|
|
|
|
e.buf.WriteString(", ")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := e.writeArrayElem(v.Index(i), depth+1); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteByte(']')
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeArrayElem writes one element of a value array. The kinds the boxed
|
|
|
|
|
|
|
|
// rules rewrite are handed to normaliseValue and the boxed writer; the rest
|
|
|
|
|
|
|
|
// write directly, including nested arrays and inline tables.
|
|
|
|
|
|
|
|
func (e *encoder) writeArrayElem(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
if v.Kind() == reflect.Interface {
|
|
|
|
|
|
|
|
if v.IsNil() {
|
|
|
|
|
|
|
|
return fmt.Errorf("interpres: cannot encode nil value")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
v = v.Elem()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
switch v.Kind() {
|
|
|
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
|
|
|
|
return e.writeArrayValue(v, depth)
|
|
|
|
|
|
|
|
case reflect.Map:
|
|
|
|
|
|
|
|
return e.writeInlineMapFromReflect(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, isMarshaler := marshalerOf(v); isMarshaler {
|
|
|
|
|
|
|
|
return e.writeNormalisedElem(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, isText, err := textValue(v); err != nil || isText {
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeNormalisedElem(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
switch v.Kind() {
|
|
|
|
|
|
|
|
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
|
|
|
|
|
|
|
|
reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
|
|
|
|
|
|
|
|
reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
|
|
|
|
|
|
|
|
if t := v.Type(); t != durationType && t != numberType {
|
|
|
|
|
|
|
|
return e.writeScalarValue(v)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeNormalisedElem(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeNormalisedElem normalises one element through the boxed rules and
|
|
|
|
|
|
|
|
// writes the result.
|
|
|
|
|
|
|
|
func (e *encoder) writeNormalisedElem(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
val, err := normaliseValueAt(v, depth)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeValue(val)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeInlineMapFromReflect renders a map from its reflect value as an inline
|
|
|
|
|
|
|
|
// table, the shape the boxed path gives the table elements of a value array:
|
|
|
|
|
|
|
|
// sorted keys, single line when it fits, across lines when it does not.
|
|
|
|
|
|
|
|
func (e *encoder) writeInlineMapFromReflect(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
if e.limit >= noInlineBreak {
|
|
|
|
|
|
|
|
return e.writeInlineMapFlatReflect(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
flat := e.flat()
|
|
|
|
|
|
|
|
err := flat.writeInlineMapFlatReflect(v, depth)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
flat.release()
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fits := e.column()+flat.buf.Len() <= e.limit
|
|
|
|
|
|
|
|
if fits {
|
|
|
|
|
|
|
|
e.buf.Write(flat.buf.Bytes())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
flat.release()
|
|
|
|
|
|
|
|
if fits {
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeInlineMapMultilineReflect(v, depth)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeInlineMapFlatReflect renders the single-line form.
|
|
|
|
|
|
|
|
func (e *encoder) writeInlineMapFlatReflect(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
if v.Type().Key().Kind() != reflect.String {
|
|
|
|
|
|
|
|
return fmt.Errorf("map key must be string, got %s", v.Type().Key())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
keys := make([]string, 0, v.Len())
|
|
|
|
|
|
|
|
for _, k := range v.MapKeys() {
|
|
|
|
|
|
|
|
keys = append(keys, k.String())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
slices.Sort(keys)
|
|
|
|
|
|
|
|
e.buf.WriteByte('{')
|
|
|
|
|
|
|
|
for i, k := range keys {
|
|
|
|
|
|
|
|
if i > 0 {
|
|
|
|
|
|
|
|
e.buf.WriteString(", ")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := e.writeKey(k); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteString(" = ")
|
|
|
|
|
|
|
|
if err := e.writeArrayElem(v.MapIndex(reflect.ValueOf(k)), depth+1); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteByte('}')
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeInlineMapMultilineReflect renders the across-lines form.
|
|
|
|
|
|
|
|
func (e *encoder) writeInlineMapMultilineReflect(v reflect.Value, depth int) error {
|
|
|
|
|
|
|
|
keys := make([]string, 0, v.Len())
|
|
|
|
|
|
|
|
for _, k := range v.MapKeys() {
|
|
|
|
|
|
|
|
keys = append(keys, k.String())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
slices.Sort(keys)
|
|
|
|
|
|
|
|
e.buf.WriteString("{\n")
|
|
|
|
|
|
|
|
e.inlineDepth++
|
|
|
|
|
|
|
|
for _, k := range keys {
|
|
|
|
|
|
|
|
e.writeInlineIndent()
|
|
|
|
|
|
|
|
if err := e.writeKey(k); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteString(" = ")
|
|
|
|
|
|
|
|
if err := e.writeArrayElem(v.MapIndex(reflect.ValueOf(k)), depth+1); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteString(",\n")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.inlineDepth--
|
|
|
|
|
|
|
|
e.writeInlineIndent()
|
|
|
|
|
|
|
|
e.buf.WriteByte('}')
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// marshalerOf finds the Marshaler a value carries: on the value itself, or on
|
|
|
|
// marshalerOf finds the Marshaler a value carries: on the value itself, or on
|
|
|
|
// its address, so a pointer-receiver MarshalTOML is found on an addressable
|
|
|
|
// its address, so a pointer-receiver MarshalTOML is found on an addressable
|
|
|
|
// struct field or slice element, exactly as textMarshalerOf finds MarshalText.
|
|
|
|
// struct field or slice element, exactly as textMarshalerOf finds MarshalText.
|
|
|
@@ -1296,13 +1521,51 @@ func (e *encoder) writeKV(ent *entry) error {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e.buf.WriteString(" = ")
|
|
|
|
e.buf.WriteString(" = ")
|
|
|
|
if err := e.writeValue(ent.val); err != nil {
|
|
|
|
if err := e.writeEntryValue(ent); err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e.buf.WriteByte('\n')
|
|
|
|
e.buf.WriteByte('\n')
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeEntryValue writes a scalar entry's value: from the reflect cell the
|
|
|
|
|
|
|
|
// walk kept when it can be written unboxed, from the boxed value otherwise.
|
|
|
|
|
|
|
|
func (e *encoder) writeEntryValue(ent *entry) error {
|
|
|
|
|
|
|
|
if ent.rv.IsValid() {
|
|
|
|
|
|
|
|
switch ent.rv.Kind() {
|
|
|
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
|
|
|
|
return e.writeArrayValue(ent.rv, 0)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeScalarValue(ent.rv)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeValue(ent.val)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeScalarValue writes a scalar from its reflect value, boxing only the
|
|
|
|
|
|
|
|
// kinds the boxed writer handles specially.
|
|
|
|
|
|
|
|
func (e *encoder) writeScalarValue(v reflect.Value) error {
|
|
|
|
|
|
|
|
switch v.Kind() {
|
|
|
|
|
|
|
|
case reflect.String:
|
|
|
|
|
|
|
|
return e.writeStringVal(v.String())
|
|
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
|
|
|
e.buf.WriteString(strconv.FormatBool(v.Bool()))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
|
|
|
|
e.buf.WriteString(strconv.FormatInt(v.Int(), 10))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
|
|
|
|
u := v.Uint()
|
|
|
|
|
|
|
|
if u > math.MaxInt64 {
|
|
|
|
|
|
|
|
return fmt.Errorf("unsigned value %d overflows int64", u)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
e.buf.WriteString(strconv.FormatUint(u, 10))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
|
|
|
|
return e.writeFloat(v.Float())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.writeValue(v.Interface())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (e *encoder) writeKeyPath(path []string) error {
|
|
|
|
func (e *encoder) writeKeyPath(path []string) error {
|
|
|
|
for i, p := range path {
|
|
|
|
for i, p := range path {
|
|
|
|
if i > 0 {
|
|
|
|
if i > 0 {
|
|
|
@@ -1573,7 +1836,7 @@ func (e *encoder) writeInlineDocEntry(ent entry) error {
|
|
|
|
case entryArray:
|
|
|
|
case entryArray:
|
|
|
|
return errInlineArrayOfTables
|
|
|
|
return errInlineArrayOfTables
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
return e.writeValue(ent.val)
|
|
|
|
return e.writeEntryValue(&ent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|