-
Notifications
You must be signed in to change notification settings - Fork 0
/
struct_info.go
101 lines (89 loc) · 2.64 KB
/
struct_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package instruct
import (
"errors"
"fmt"
"io"
"reflect"
"strings"
)
// structInfo caches struct field configurations.
type structInfo struct {
typ reflect.Type // non-pointer final type (from "field.Type()")
field reflect.StructField // field, empty on root struct
tag *Tag // tag
path []string // complete field path including itself, using the unmodified struct field name
fields []*structInfo // child fields
}
func (s *structInfo) fullFieldName() string {
return strings.Join(s.path, ".")
}
func (s *structInfo) checkSameType(t reflect.Type) error {
t = reflectElem(t)
if t != s.typ {
return fmt.Errorf("invalid data type, expected %s got %s", s.typ.String(), t.String())
}
return nil
}
func (s *structInfo) findField(f reflect.StructField) *structInfo {
for _, field := range s.fields {
if intSliceEquals(field.field.Index, f.Index) {
return field
}
}
return nil
}
func (s *structInfo) fieldByName(name string) *structInfo {
for _, field := range s.fields {
if field.field.Name == name {
return field
}
}
return nil
}
func (s *structInfo) dump(w io.Writer) error {
return s.dumpIndent("", w)
}
func (s *structInfo) dumpIndent(indent string, w io.Writer) error {
var ferr error
var err error
_, err = fmt.Fprintf(w, "%s- ", indent)
ferr = errors.Join(ferr, err)
name := "{ROOT}"
if s.field.Type != nil {
name = s.field.Name
}
_, err = fmt.Fprintf(w, "%s [/%s] (type: %s, kind: %s) ", name, strings.Join(s.path, "/"), s.typ.Name(), s.typ.Kind().String())
ferr = errors.Join(ferr, err)
if s.field.Type != nil {
_, err = fmt.Fprintf(w, "[field type: %s, kind: %s] ", s.field.Type.String(), s.field.Type.Kind().String())
ferr = errors.Join(ferr, err)
// _, err = fmt.Fprintf(w, "[path: '%s']", strings.Join(s.path, "/"))
// ferr = errors.Join(ferr, err)
}
_, err = fmt.Fprintf(w, "\n")
ferr = errors.Join(ferr, err)
for _, field := range s.fields {
ferr = errors.Join(ferr, field.dumpIndent(indent+"\t", w))
}
return err
}
// structInfoWithMapTags overrides a structInfo with a MapTags. This creates a clone of all the objects and don't
// change the original in any way.
func structInfoWithMapTags[IT any, DC DecodeContext](si *structInfo, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
ctx := &buildContext{
clone: true,
skipStructField: true,
skipStructOption: true,
}
newsi, err := buildStructInfoItem(ctx, si, level{}, mapTags, options)
if err != nil {
return nil, err
}
if mapTags != nil {
err = mapTags.checkUnusedFields(ctx.GetUsedValues(mapTagValueKey))
if err != nil {
return nil, err
}
}
return newsi, nil
}