Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -275,7 +275,7 @@ func buildOrderedDoc(om *OrderedMap, doc *tomlDoc, path encPath) error {
|
||||
// A nil value has no TOML form, the rule nil pointer fields follow.
|
||||
continue
|
||||
}
|
||||
if err := addField(doc, key, rv, path); err != nil {
|
||||
if err := addField(doc, key, rv, path, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -304,6 +304,10 @@ type entry struct {
|
||||
doc *tomlDoc // entryTable
|
||||
docs []*tomlDoc
|
||||
|
||||
// inline forces a table entry to emit as `key = {…}`; it is set by the
|
||||
// `,inline` tag option. An array of tables keeps the header form.
|
||||
inline bool
|
||||
|
||||
// emitted records that the grouped emission wrote this table inline, so
|
||||
// the header pass that follows skips it. The representation is built
|
||||
// fresh per Marshal call.
|
||||
@@ -347,8 +351,10 @@ func (d *tomlDoc) addScalar(key string, val any) {
|
||||
d.entries = append(d.entries, entry{kind: entryScalar, key: key, val: val})
|
||||
}
|
||||
|
||||
func (d *tomlDoc) addTable(key string, sub *tomlDoc) {
|
||||
d.entries = append(d.entries, entry{kind: entryTable, key: key, doc: sub})
|
||||
func (d *tomlDoc) addTable(key string, sub *tomlDoc) *entry {
|
||||
e := entry{kind: entryTable, key: key, doc: sub}
|
||||
d.entries = append(d.entries, e)
|
||||
return &d.entries[len(d.entries)-1]
|
||||
}
|
||||
|
||||
func (d *tomlDoc) addArray(key string, subs []*tomlDoc) {
|
||||
@@ -482,7 +488,7 @@ func walkStructDoc(v reflect.Value, doc *tomlDoc, path encPath, prefix []int, sc
|
||||
if fieldOmitted(f, v.Field(i)) {
|
||||
continue
|
||||
}
|
||||
if err := addField(doc, name, v.Field(i), path); err != nil {
|
||||
if err := addField(doc, name, v.Field(i), path, tagHasOption(f.Tag.Get("toml"), "inline")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -493,30 +499,69 @@ func walkStructDoc(v reflect.Value, doc *tomlDoc, path encPath, prefix []int, sc
|
||||
// state decides through that method before reflection is consulted.
|
||||
type isZeroer interface{ IsZero() bool }
|
||||
|
||||
// tagOptions returns the option part of a `toml` tag, the part after the
|
||||
// first comma.
|
||||
func tagOptions(tag string) string {
|
||||
_, opts, _ := strings.Cut(tag, ",")
|
||||
return opts
|
||||
}
|
||||
|
||||
// tagHasOption reports whether want is one of the tag's comma-separated
|
||||
// options.
|
||||
func tagHasOption(tag, want string) bool {
|
||||
opts := tagOptions(tag)
|
||||
for opts != "" {
|
||||
var opt string
|
||||
opt, opts, _ = strings.Cut(opts, ",")
|
||||
if opt == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// fieldOmitted reports whether the field's tag options drop it from the
|
||||
// output: omitzero skips the zero value of the field's type, omitempty skips
|
||||
// an empty collection (slice, array, or map). The decoder ignores both
|
||||
// options; they shape emission only.
|
||||
// an empty value in the encoding/json sense, an empty string, a zero number,
|
||||
// false, a nil pointer or interface, and an empty slice, array or map. The
|
||||
// decoder ignores both options; they shape emission only.
|
||||
func fieldOmitted(f reflect.StructField, v reflect.Value) bool {
|
||||
tag, ok := f.Tag.Lookup("toml")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_, opts, _ := strings.Cut(tag, ",")
|
||||
for opts != "" {
|
||||
var opt string
|
||||
opt, opts, _ = strings.Cut(opts, ",")
|
||||
switch opt {
|
||||
case "omitzero":
|
||||
if isZeroValue(v) {
|
||||
if tagHasOption(tag, "omitzero") && isZeroValue(v) {
|
||||
return true
|
||||
}
|
||||
if tagHasOption(tag, "omitempty") {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice, reflect.Array, reflect.Map:
|
||||
if v.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
case "omitempty":
|
||||
switch v.Kind() {
|
||||
case reflect.Slice, reflect.Array, reflect.Map:
|
||||
if v.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.String:
|
||||
if v.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.Bool:
|
||||
if !v.Bool() {
|
||||
return true
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if v.Int() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if v.Uint() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if v.Float() == 0 {
|
||||
return true
|
||||
}
|
||||
case reflect.Pointer, reflect.Interface:
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -569,7 +614,7 @@ func buildMapDoc(v reflect.Value, doc *tomlDoc, path encPath) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := addField(doc, k.String(), v.MapIndex(k), path); err != nil {
|
||||
if err := addField(doc, k.String(), v.MapIndex(k), path, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -584,7 +629,11 @@ func buildMapDoc(v reflect.Value, doc *tomlDoc, path encPath) error {
|
||||
// contract violation.
|
||||
var errNilMarshalTOML = errors.New("MarshalTOML returned a nil value")
|
||||
|
||||
func addField(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
// addField adds one value under name, the shape addField picks deciding
|
||||
// whether it is a scalar line, a sub-table or an array. forceInline marks a
|
||||
// table-valued field carrying the `,inline` tag option: it emits as
|
||||
// `key = {…}` instead of a header section.
|
||||
func addField(doc *tomlDoc, name string, v reflect.Value, path encPath, forceInline bool) error {
|
||||
if m, ok := marshalerOf(v); ok {
|
||||
mv, err := m.MarshalTOML()
|
||||
if err != nil {
|
||||
@@ -624,7 +673,7 @@ func addField(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
if err := buildOrderedDoc(&om, sub, path.key(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
doc.addTable(name, sub)
|
||||
doc.addTable(name, sub).inline = forceInline
|
||||
return nil
|
||||
}
|
||||
switch v.Kind() {
|
||||
@@ -633,11 +682,11 @@ func addField(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
doc.addScalar(name, v.Interface())
|
||||
return nil
|
||||
}
|
||||
return addSubTable(doc, name, v, path)
|
||||
return addSubTable(doc, name, v, path, forceInline)
|
||||
case reflect.Map:
|
||||
return addSubTable(doc, name, v, path)
|
||||
return addSubTable(doc, name, v, path, forceInline)
|
||||
case reflect.Slice, reflect.Array:
|
||||
return addArrayValue(doc, name, v, path)
|
||||
return addArrayValue(doc, name, v, path, forceInline)
|
||||
default:
|
||||
val, err := normaliseValue(v)
|
||||
if err != nil {
|
||||
@@ -648,7 +697,7 @@ func addField(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
}
|
||||
}
|
||||
|
||||
func addSubTable(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
func addSubTable(doc *tomlDoc, name string, v reflect.Value, path encPath, forceInline bool) error {
|
||||
sub := &tomlDoc{ctx: doc.ctx, opts: doc.opts, depth: doc.depth + 1}
|
||||
if atDepthLimit(sub.depth) {
|
||||
return &EncodeError{Path: path.key(name).String(), Err: errDepthLimit()}
|
||||
@@ -663,11 +712,11 @@ func addSubTable(doc *tomlDoc, name string, v reflect.Value, path encPath) error
|
||||
return err
|
||||
}
|
||||
}
|
||||
doc.addTable(name, sub)
|
||||
doc.addTable(name, sub).inline = forceInline
|
||||
return nil
|
||||
}
|
||||
|
||||
func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath, forceInline bool) error {
|
||||
if v.Kind() == reflect.Slice && v.IsNil() {
|
||||
// A nil slice has no explicit representation in TOML, so it is skipped.
|
||||
return nil
|
||||
@@ -723,6 +772,11 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath) err
|
||||
if v.Type().Elem().Kind() == reflect.Interface {
|
||||
allTables = false
|
||||
}
|
||||
// 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.
|
||||
if forceInline && allTables {
|
||||
return &EncodeError{Path: path.key(name).String(), Err: errors.New("an array of tables has no inline form")}
|
||||
}
|
||||
if allTables {
|
||||
subs := make([]*tomlDoc, n)
|
||||
for i, ev := range elems {
|
||||
@@ -1104,7 +1158,7 @@ func (e *encoder) emitDoc(doc *tomlDoc, prefix []string) error {
|
||||
if t.kind != entryTable {
|
||||
continue
|
||||
}
|
||||
inlined, err := e.writeInlineSubTableIfSmall(t.key, t.doc)
|
||||
inlined, err := e.writeInlineSubTableIfSmall(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1159,7 +1213,7 @@ func (e *encoder) emitDoc(doc *tomlDoc, prefix []string) error {
|
||||
return err
|
||||
}
|
||||
case entryTable:
|
||||
inlined, err := e.writeInlineSubTableIfSmall(ent.key, ent.doc)
|
||||
inlined, err := e.writeInlineSubTableIfSmall(&ent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1516,29 +1570,34 @@ func (e *encoder) writeInlineDocMultiline(doc *tomlDoc) error {
|
||||
|
||||
// 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) {
|
||||
// so. An entry the `,inline` tag option marks is written regardless of the
|
||||
// threshold. 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; a forced
|
||||
// inline of one is an error rather than a silent form change.
|
||||
func (e *encoder) writeInlineSubTableIfSmall(t *entry) (bool, error) {
|
||||
if !t.inline && (e.opts.inlineTablesAt <= 0 || !inlinableDoc(t.doc)) {
|
||||
return false, nil
|
||||
}
|
||||
if !inlinableDoc(t.doc) {
|
||||
return false, fmt.Errorf("interpres: field %q holds an array of tables and has no inline form", t.key)
|
||||
}
|
||||
flat := e.flat()
|
||||
if err := flat.writeInlineDoc(doc); err != nil {
|
||||
if err := flat.writeInlineDoc(t.doc); err != nil {
|
||||
flat.release()
|
||||
return false, err
|
||||
}
|
||||
if flat.buf.Len() > e.opts.inlineTablesAt {
|
||||
if !t.inline && flat.buf.Len() > e.opts.inlineTablesAt {
|
||||
flat.release()
|
||||
return false, nil
|
||||
}
|
||||
if err := e.writeKey(name); err != nil {
|
||||
if err := e.writeKey(t.key); err != nil {
|
||||
flat.release()
|
||||
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 {
|
||||
} else if err := e.writeInlineDocMultiline(t.doc); err != nil {
|
||||
flat.release()
|
||||
return false, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user