Skip to content

Commit de86170

Browse files
committed
refactor
1 parent a1ca14f commit de86170

File tree

2 files changed

+119
-113
lines changed

2 files changed

+119
-113
lines changed

struct_info.go

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -45,102 +45,6 @@ func (s *structInfo) fieldByName(name string) *structInfo {
4545
return nil
4646
}
4747

48-
func buildStructInfo[IT any, DC DecodeContext](t reflect.Type, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
49-
ctx := &buildContext{}
50-
51-
t = reflectElem(t)
52-
53-
// parse struct option if available
54-
tag, err := parseStructTagStructOption(ctx, t, level{}, mapTags, &options)
55-
if err != nil {
56-
return nil, err
57-
}
58-
59-
// build struct info for root struct.
60-
si, err := buildStructInfoItem(ctx, &structInfo{
61-
typ: t,
62-
tag: tag,
63-
}, level{}, mapTags, options)
64-
if err != nil {
65-
return nil, err
66-
}
67-
68-
if mapTags != nil {
69-
// check unused defaultMapTags keys
70-
err = mapTags.checkUnusedFields(ctx.GetUsedValues(mapTagValueKey))
71-
if err != nil {
72-
return nil, err
73-
}
74-
}
75-
76-
return si, err
77-
}
78-
79-
// buildStructInfoItem builds a structInfo for the fields of the passed struct.
80-
// This function is used both to create a new structInfo and override one with new MapTags. In the former case,
81-
// it returns copies of the fields and don't change the original.
82-
func buildStructInfoItem[IT any, DC DecodeContext](ctx *buildContext, si *structInfo, lvl level, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
83-
siBuild := buildCloneStructInfo(ctx, si, false)
84-
85-
if siBuild.tag != nil && siBuild.tag.IsSO {
86-
// check struct option
87-
if siBuild.tag.Operation == OperationIgnore {
88-
return nil, fmt.Errorf("cannot ignore struct option for field '%s'", lvl.StringPath())
89-
}
90-
91-
// if not recursing, skip checking fields
92-
if !siBuild.tag.SORecurse {
93-
return siBuild, nil
94-
}
95-
}
96-
97-
for i := 0; i < siBuild.typ.NumField(); i++ {
98-
field := siBuild.typ.Field(i)
99-
if !field.IsExported() || isOptionField(field) {
100-
continue
101-
}
102-
103-
curlevel := lvl.Append(field.Name)
104-
sifield := si.findField(field)
105-
if sifield != nil {
106-
sifield = buildCloneStructInfo(ctx, sifield, true)
107-
} else {
108-
sifield = &structInfo{
109-
typ: reflectElem(field.Type),
110-
field: field,
111-
path: curlevel.Path(),
112-
}
113-
}
114-
115-
// parse struct tag or equivalent map tag.
116-
if tag, err := parseStructTag(ctx, field, curlevel, mapTags, &options); err != nil {
117-
return nil, fmt.Errorf("error on field '%s': %w", curlevel.StringPath(), err)
118-
} else if tag != nil {
119-
sifield.tag = tag
120-
}
121-
122-
if sifield.tag == nil {
123-
return nil, fmt.Errorf("field '%s' configuration not found", curlevel.StringPath())
124-
}
125-
126-
if sifield.tag.Operation == OperationRecurse {
127-
// recurse into inner struct
128-
if !isStruct(field.Type) {
129-
return nil, fmt.Errorf("field '%s' must be a struct to use recurse but is '%s'", field.Name, field.Type.String())
130-
}
131-
var err error
132-
sifield, err = buildStructInfoItem(ctx, sifield, lvl.AppendIfTrue(!field.Anonymous, field.Name), mapTags, options)
133-
if err != nil {
134-
return nil, err
135-
}
136-
}
137-
138-
siBuild.fields = append(siBuild.fields, sifield)
139-
}
140-
141-
return siBuild, nil
142-
}
143-
14448
// structInfoWithMapTags overrides a structInfo with a MapTags. This creates a clone of all the objects and don't
14549
// change the original in any way.
14650
func structInfoWithMapTags[IT any, DC DecodeContext](si *structInfo, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
@@ -164,20 +68,3 @@ func structInfoWithMapTags[IT any, DC DecodeContext](si *structInfo, mapTags Map
16468

16569
return newsi, nil
16670
}
167-
168-
// buildCloneStructInfo clones a structInfo if ctx.clone is true, otherwise just return the original one.
169-
func buildCloneStructInfo(ctx *buildContext, si *structInfo, withFields bool) *structInfo {
170-
if !ctx.clone {
171-
return si
172-
}
173-
ret := &structInfo{
174-
typ: si.typ,
175-
field: si.field,
176-
tag: si.tag,
177-
path: si.path,
178-
}
179-
if withFields {
180-
ret.fields = si.fields
181-
}
182-
return ret
183-
}

struct_info_build.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package instruct
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
)
7+
8+
func buildStructInfo[IT any, DC DecodeContext](t reflect.Type, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
9+
ctx := &buildContext{}
10+
11+
t = reflectElem(t)
12+
13+
// parse struct option if available
14+
tag, err := parseStructTagStructOption(ctx, t, level{}, mapTags, &options)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
// build struct info for root struct.
20+
si, err := buildStructInfoItem(ctx, &structInfo{
21+
typ: t,
22+
tag: tag,
23+
}, level{}, mapTags, options)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
if mapTags != nil {
29+
// check unused defaultMapTags keys
30+
err = mapTags.checkUnusedFields(ctx.GetUsedValues(mapTagValueKey))
31+
if err != nil {
32+
return nil, err
33+
}
34+
}
35+
36+
return si, err
37+
}
38+
39+
// buildStructInfoItem builds a structInfo for the fields of the passed struct.
40+
// This function is used both to create a new structInfo and override one with new MapTags. In the former case,
41+
// it returns copies of the fields and don't change the original.
42+
func buildStructInfoItem[IT any, DC DecodeContext](ctx *buildContext, si *structInfo, lvl level, mapTags MapTags, options DefaultOptions[IT, DC]) (*structInfo, error) {
43+
siBuild := buildCloneStructInfo(ctx, si, false)
44+
45+
if siBuild.tag != nil && siBuild.tag.IsSO {
46+
// check struct option
47+
if siBuild.tag.Operation == OperationIgnore {
48+
return nil, fmt.Errorf("cannot ignore struct option for field '%s'", lvl.StringPath())
49+
}
50+
51+
// if not recursing, skip checking fields
52+
if !siBuild.tag.SORecurse {
53+
return siBuild, nil
54+
}
55+
}
56+
57+
for i := 0; i < siBuild.typ.NumField(); i++ {
58+
field := siBuild.typ.Field(i)
59+
if !field.IsExported() || isOptionField(field) {
60+
continue
61+
}
62+
63+
curlevel := lvl.Append(field.Name)
64+
sifield := si.findField(field)
65+
if sifield != nil {
66+
sifield = buildCloneStructInfo(ctx, sifield, true)
67+
} else {
68+
sifield = &structInfo{
69+
typ: reflectElem(field.Type),
70+
field: field,
71+
path: curlevel.Path(),
72+
}
73+
}
74+
75+
// parse struct tag or equivalent map tag.
76+
if tag, err := parseStructTag(ctx, field, curlevel, mapTags, &options); err != nil {
77+
return nil, fmt.Errorf("error on field '%s': %w", curlevel.StringPath(), err)
78+
} else if tag != nil {
79+
sifield.tag = tag
80+
}
81+
82+
if sifield.tag == nil {
83+
return nil, fmt.Errorf("field '%s' configuration not found", curlevel.StringPath())
84+
}
85+
86+
if sifield.tag.Operation == OperationRecurse {
87+
// recurse into inner struct
88+
if !isStruct(field.Type) {
89+
return nil, fmt.Errorf("field '%s' must be a struct to use recurse but is '%s'", field.Name, field.Type.String())
90+
}
91+
var err error
92+
sifield, err = buildStructInfoItem(ctx, sifield, lvl.AppendIfTrue(!field.Anonymous, field.Name), mapTags, options)
93+
if err != nil {
94+
return nil, err
95+
}
96+
}
97+
98+
siBuild.fields = append(siBuild.fields, sifield)
99+
}
100+
101+
return siBuild, nil
102+
}
103+
104+
// buildCloneStructInfo clones a structInfo if ctx.clone is true, otherwise just return the original one.
105+
func buildCloneStructInfo(ctx *buildContext, si *structInfo, withFields bool) *structInfo {
106+
if !ctx.clone {
107+
return si
108+
}
109+
ret := &structInfo{
110+
typ: si.typ,
111+
field: si.field,
112+
tag: si.tag,
113+
path: si.path,
114+
}
115+
if withFields {
116+
ret.fields = si.fields
117+
}
118+
return ret
119+
}

0 commit comments

Comments
 (0)