@@ -24,6 +24,9 @@ type FieldInfo struct {
2424 Embedded bool
2525 Children []* FieldInfo
2626 Parent * FieldInfo
27+
28+ Virtual bool
29+ VirtualType reflect.Type
2730}
2831
2932// A StructMap is an index of field metadata for a struct.
@@ -39,6 +42,11 @@ func (f StructMap) GetByPath(path string) *FieldInfo {
3942 return f .Paths [path ]
4043}
4144
45+ // GetByPath returns a *FieldInfo for a given string name.
46+ func (f StructMap ) GetByName (name string ) * FieldInfo {
47+ return f .Names [name ]
48+ }
49+
4250// GetByTraversal returns a *FieldInfo for a given integer path. It is
4351// analogous to reflect.FieldByIndex, but using the cached traversal
4452// rather than re-executing the reflect machinery each time.
@@ -57,11 +65,15 @@ func (f StructMap) GetByTraversal(index []int) *FieldInfo {
5765 return tree
5866}
5967
68+ type Register = map [reflect.Type ]map [string ]reflect.Type
69+
6070// Mapper is a general purpose mapper of names to struct fields. A Mapper
6171// behaves like most marshallers in the standard library, obeying a field tag
6272// for name mapping but also providing a basic transform function.
6373type Mapper struct {
64- cache map [reflect.Type ]* StructMap
74+ cache map [reflect.Type ]* StructMap
75+ registry Register
76+
6577 tagName string
6678 tagMapFunc func (string ) string
6779 mapFunc func (string ) string
@@ -72,8 +84,9 @@ type Mapper struct {
7284// If tagName is the empty string, it is ignored.
7385func NewMapper (tagName string ) * Mapper {
7486 return & Mapper {
75- cache : make (map [reflect.Type ]* StructMap ),
76- tagName : tagName ,
87+ cache : make (map [reflect.Type ]* StructMap ),
88+ registry : make (Register ),
89+ tagName : tagName ,
7790 }
7891}
7992
@@ -83,6 +96,7 @@ func NewMapper(tagName string) *Mapper {
8396func NewMapperTagFunc (tagName string , mapFunc , tagMapFunc func (string ) string ) * Mapper {
8497 return & Mapper {
8598 cache : make (map [reflect.Type ]* StructMap ),
99+ registry : make (Register ),
86100 tagName : tagName ,
87101 mapFunc : mapFunc ,
88102 tagMapFunc : tagMapFunc ,
@@ -94,19 +108,32 @@ func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *
94108// for any other field, the mapped name will be f(field.Name)
95109func NewMapperFunc (tagName string , f func (string ) string ) * Mapper {
96110 return & Mapper {
97- cache : make (map [reflect.Type ]* StructMap ),
98- tagName : tagName ,
99- mapFunc : f ,
111+ cache : make (map [reflect.Type ]* StructMap ),
112+ registry : make (Register ),
113+ tagName : tagName ,
114+ mapFunc : f ,
100115 }
101116}
102117
118+ //
119+ //
120+ func (m * Mapper ) Register (t reflect.Type , name string , vf reflect.Type ) {
121+ vfs := m .registry [t ]
122+ if vfs == nil {
123+ vfs = make (map [string ]reflect.Type )
124+ m .registry [t ] = vfs
125+ }
126+
127+ vfs [name ] = vf
128+ }
129+
103130// TypeMap returns a mapping of field strings to int slices representing
104131// the traversal down the struct to reach the field.
105132func (m * Mapper ) TypeMap (t reflect.Type ) * StructMap {
106133 m .mutex .Lock ()
107134 mapping , ok := m .cache [t ]
108135 if ! ok {
109- mapping = getMapping (t , m .tagName , m .mapFunc , m .tagMapFunc )
136+ mapping = getMapping (t , m .tagName , m .mapFunc , m .tagMapFunc , m )
110137 m .cache [t ] = mapping
111138 }
112139 m .mutex .Unlock ()
@@ -122,7 +149,7 @@ func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
122149 r := map [string ]reflect.Value {}
123150 tm := m .TypeMap (v .Type ())
124151 for tagName , fi := range tm .Names {
125- r [tagName ] = FieldByIndexes (v , fi .Index )
152+ r [tagName ] = FieldByIndexes (v , fi .Index , m )
126153 }
127154 return r
128155}
@@ -139,7 +166,7 @@ func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
139166 if ! ok {
140167 return v
141168 }
142- return FieldByIndexes (v , fi .Index )
169+ return FieldByIndexes (v , fi .Index , m )
143170}
144171
145172// FieldsByName returns a slice of values corresponding to the slice of names
@@ -156,7 +183,7 @@ func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
156183 if ! ok {
157184 vals = append (vals , * new (reflect.Value ))
158185 } else {
159- vals = append (vals , FieldByIndexes (v , fi .Index ))
186+ vals = append (vals , FieldByIndexes (v , fi .Index , m ))
160187 }
161188 }
162189 return vals
@@ -203,16 +230,28 @@ func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(in
203230
204231// FieldByIndexes returns a value for the field given by the struct traversal
205232// for the given value.
206- func FieldByIndexes (v reflect.Value , indexes []int ) reflect.Value {
233+ func FieldByIndexes (v reflect.Value , indexes []int , m * Mapper ) reflect.Value {
234+ tm := m .TypeMap (v .Type ())
235+ fi := tm .Tree
207236 for _ , i := range indexes {
208- v = reflect .Indirect (v ).Field (i )
209- // if this is a pointer and it's nil, allocate a new value and set it
210- if v .Kind () == reflect .Ptr && v .IsNil () {
211- alloc := reflect .New (Deref (v .Type ()))
212- v .Set (alloc )
213- }
214- if v .Kind () == reflect .Map && v .IsNil () {
215- v .Set (reflect .MakeMap (v .Type ()))
237+ fi = fi .Children [i ]
238+ if ! fi .Virtual {
239+ v = reflect .Indirect (v ).Field (i )
240+ // if this is a pointer and it's nil, allocate a new value and set it
241+ if v .Kind () == reflect .Ptr && v .IsNil () {
242+ alloc := reflect .New (Deref (v .Type ()))
243+ v .Set (alloc )
244+ }
245+ if v .Kind () == reflect .Map && v .IsNil () {
246+ v .Set (reflect .MakeMap (v .Type ()))
247+ }
248+ } else {
249+ alloc := reflect .New (Deref (fi .VirtualType ))
250+
251+ method := alloc .MethodByName ("SetDelegateField" )
252+ method .Call ([]reflect.Value {v })
253+
254+ return alloc
216255 }
217256 }
218257 return v
@@ -340,7 +379,7 @@ func parseOptions(tag string) map[string]string {
340379
341380// getMapping returns a mapping for the t type, using the tagName, mapFunc and
342381// tagMapFunc to determine the canonical names of fields.
343- func getMapping (t reflect.Type , tagName string , mapFunc , tagMapFunc mapf ) * StructMap {
382+ func getMapping (t reflect.Type , tagName string , mapFunc , tagMapFunc mapf , mapper * Mapper ) * StructMap {
344383 m := []* FieldInfo {}
345384
346385 root := & FieldInfo {}
@@ -361,6 +400,34 @@ QueueLoop:
361400 }
362401
363402 nChildren := 0
403+ if fields , ok := mapper .registry [tq .t ]; ok {
404+ nChildren = len (fields )
405+ tq .fi .Children = make ([]* FieldInfo , nChildren )
406+ fieldPos := 0
407+ for name , field := range fields {
408+ //f := tq.t.Field(fieldPos)
409+ fi := FieldInfo {
410+ Field : reflect.StructField {},
411+ Name : name ,
412+ Zero : reflect .New (field ).Elem (),
413+ Virtual : true ,
414+ VirtualType : field ,
415+ }
416+
417+ if tq .pp == "" {
418+ fi .Path = fi .Name
419+ } else {
420+ fi .Path = tq .pp + "." + fi .Name
421+ }
422+
423+ fi .Index = apnd (tq .fi .Index , fieldPos )
424+ fi .Parent = tq .fi
425+ tq .fi .Children [fieldPos ] = & fi
426+ m = append (m , & fi )
427+ }
428+ continue
429+ }
430+
364431 if tq .t .Kind () == reflect .Struct {
365432 nChildren = tq .t .NumField ()
366433 }
@@ -435,5 +502,23 @@ QueueLoop:
435502 }
436503 }
437504
505+ duplicatedNames := make (map [string ]bool )
506+ for _ , fi := range flds .Index {
507+ if fi .Name != "" && ! fi .Embedded {
508+ fld , ok := flds .Names [fi .Name ]
509+ if ok {
510+ if fld .Parent .Parent != nil { // not first level field
511+ duplicatedNames [fi .Name ] = true
512+ }
513+ } else {
514+ flds .Names [fi .Name ] = fi
515+ }
516+ }
517+ }
518+
519+ for key := range duplicatedNames {
520+ delete (flds .Names , key )
521+ }
522+
438523 return flds
439524}
0 commit comments