Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -184,6 +184,13 @@ func (e *encoder) encode(v any) error {
|
||||
return fmt.Errorf("interpres: cannot marshal a Document; marshal its Map() to write the values")
|
||||
case Document:
|
||||
return fmt.Errorf("interpres: cannot marshal a Document; marshal its Map() to write the values")
|
||||
case OrderedMap:
|
||||
return e.encodeOrderedMap(&x)
|
||||
case *OrderedMap:
|
||||
if x == nil {
|
||||
return fmt.Errorf("interpres: cannot marshal nil value")
|
||||
}
|
||||
return e.encodeOrderedMap(x)
|
||||
}
|
||||
rv := reflect.ValueOf(v)
|
||||
if !rv.IsValid() {
|
||||
@@ -212,6 +219,63 @@ func (e *encoder) encode(v any) error {
|
||||
return e.emitDoc(doc, nil)
|
||||
}
|
||||
|
||||
// encodeOrderedMap emits an OrderedMap as a document, its keys in the order
|
||||
// they were set, which is the reason the type exists.
|
||||
func (e *encoder) encodeOrderedMap(om *OrderedMap) error {
|
||||
if err := e.checkCtx(); err != nil {
|
||||
return err
|
||||
}
|
||||
doc := &tomlDoc{ctx: e.ctx, opts: e.opts}
|
||||
if err := buildOrderedDoc(om, doc, encPath{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.emitDoc(doc, nil)
|
||||
}
|
||||
|
||||
// buildOrderedDoc adds the entries of om to doc in the order its keys were
|
||||
// set. Nested OrderedMaps recurse; every other value goes through addField,
|
||||
// which resolves Marshaler, text and the ordinary kinds the same way it does
|
||||
// for a struct field.
|
||||
func buildOrderedDoc(om *OrderedMap, doc *tomlDoc, path encPath) error {
|
||||
if cap(doc.entries) == 0 {
|
||||
doc.entries = make([]entry, 0, om.Len())
|
||||
}
|
||||
for _, key := range om.Keys() {
|
||||
if err := doc.checkCtx(); err != nil {
|
||||
return err
|
||||
}
|
||||
val := om.values[key]
|
||||
switch x := val.(type) {
|
||||
case OrderedMap:
|
||||
sub := &tomlDoc{ctx: doc.ctx, opts: doc.opts}
|
||||
if err := buildOrderedDoc(&x, sub, path.key(key)); err != nil {
|
||||
return err
|
||||
}
|
||||
doc.addTable(key, sub)
|
||||
continue
|
||||
case *OrderedMap:
|
||||
if x == nil {
|
||||
continue
|
||||
}
|
||||
sub := &tomlDoc{ctx: doc.ctx, opts: doc.opts}
|
||||
if err := buildOrderedDoc(x, sub, path.key(key)); err != nil {
|
||||
return err
|
||||
}
|
||||
doc.addTable(key, sub)
|
||||
continue
|
||||
}
|
||||
rv := reflect.ValueOf(val)
|
||||
if !rv.IsValid() {
|
||||
// A nil value has no TOML form, the rule nil pointer fields follow.
|
||||
continue
|
||||
}
|
||||
if err := addField(doc, key, rv, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- intermediate representation -----------------------------------------
|
||||
|
||||
// entryKind discriminates the three forms an entry in a tomlDoc may take.
|
||||
@@ -518,6 +582,15 @@ func addField(doc *tomlDoc, name string, v reflect.Value, path encPath) error {
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Type() == orderedMapType {
|
||||
om := v.Interface().(OrderedMap)
|
||||
sub := &tomlDoc{ctx: doc.ctx, opts: doc.opts}
|
||||
if err := buildOrderedDoc(&om, sub, path.key(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
doc.addTable(name, sub)
|
||||
return nil
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
if isScalarStruct(v.Type()) {
|
||||
@@ -620,15 +693,20 @@ func addArrayValue(doc *tomlDoc, name string, v reflect.Value, path encPath) err
|
||||
}
|
||||
}
|
||||
sub := &tomlDoc{ctx: doc.ctx, opts: doc.opts}
|
||||
switch ev.Kind() {
|
||||
case reflect.Struct:
|
||||
switch {
|
||||
case ev.Type() == orderedMapType:
|
||||
om := ev.Interface().(OrderedMap)
|
||||
if err := buildOrderedDoc(&om, sub, apath.elem(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
case ev.Kind() == reflect.Struct:
|
||||
if isScalarStruct(ev.Type()) {
|
||||
return &EncodeError{Path: apath.elem(i).String(), Err: errors.New("heterogeneous array contains scalar")}
|
||||
}
|
||||
if err := buildStructDoc(ev, sub, apath.elem(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Map:
|
||||
case ev.Kind() == reflect.Map:
|
||||
if err := buildMapDoc(ev, sub, apath.elem(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -717,6 +795,9 @@ func resolveElement(v reflect.Value, path encPath) (reflect.Value, error) {
|
||||
// nested-array representations the emitter understands. Slices and arrays are
|
||||
// recursively normalised so that nested arrays (e.g. [][]int) work.
|
||||
func normaliseValue(v reflect.Value) (any, error) {
|
||||
if !v.IsValid() {
|
||||
return nil, fmt.Errorf("cannot encode nil value")
|
||||
}
|
||||
// Map and slice elements arrive wrapped in interface{}; look through them.
|
||||
for v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
v = v.Elem()
|
||||
@@ -755,6 +836,20 @@ func normaliseValue(v reflect.Value) (any, error) {
|
||||
if v.Type() == numberType {
|
||||
return Number(v.String()), nil
|
||||
}
|
||||
// An OrderedMap in a value array has no header form, so it renders as an
|
||||
// ordinary inline table, whose keys come out sorted.
|
||||
if v.Type() == orderedMapType {
|
||||
om := v.Interface().(OrderedMap)
|
||||
out := make(map[string]any, om.Len())
|
||||
for _, k := range om.Keys() {
|
||||
val, err := normaliseValue(reflect.ValueOf(om.values[k]))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[%s]: %w", k, err)
|
||||
}
|
||||
out[k] = val
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
// A type that renders itself as text becomes a TOML string, scalar kinds
|
||||
// and structs alike.
|
||||
s, isText, err := textValue(v)
|
||||
|
||||
Reference in New Issue
Block a user