Alejandro Mery
1 year ago
5 changed files with 166 additions and 5 deletions
@ -0,0 +1,16 @@ |
|||||||
|
package reflection |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"reflect" |
||||||
|
) |
||||||
|
|
||||||
|
func structFieldName(sf reflect.StructField) string { |
||||||
|
if sf.Anonymous { |
||||||
|
idx := sf.Index[len(sf.Index)-1] |
||||||
|
|
||||||
|
return fmt.Sprintf("%s-%v", "anonymous", idx) |
||||||
|
} |
||||||
|
|
||||||
|
return sf.Name |
||||||
|
} |
@ -1,5 +1,37 @@ |
|||||||
package reflection |
package reflection |
||||||
|
|
||||||
func (*Reflection) scan() error { |
import ( |
||||||
|
"reflect" |
||||||
|
) |
||||||
|
|
||||||
|
func (r *Reflection) scanType(rt reflect.Type) error { |
||||||
|
switch rt.Kind() { |
||||||
|
case reflect.Pointer, reflect.Slice: |
||||||
|
rt = rt.Elem() |
||||||
|
} |
||||||
|
|
||||||
|
if _, ok := r.types[rt]; ok { |
||||||
|
// cached
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
ti, err := NewTypeInfo(rt) |
||||||
|
if err != nil { |
||||||
|
return &UnmarshalTypeError{Type: rt, Err: err} |
||||||
|
} |
||||||
|
|
||||||
|
r.types[rt] = ti |
||||||
|
|
||||||
|
for i := range ti.fields { |
||||||
|
err := r.scanType(ti.fields[i].sf.Type) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
return nil |
return nil |
||||||
} |
} |
||||||
|
|
||||||
|
func (r *Reflection) scan() error { |
||||||
|
return r.scanType(r.v.Type()) |
||||||
|
} |
||||||
|
@ -0,0 +1,108 @@ |
|||||||
|
package reflection |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
"reflect" |
||||||
|
|
||||||
|
"github.com/fatih/structtag" |
||||||
|
"github.com/pkg/errors" |
||||||
|
) |
||||||
|
|
||||||
|
// TypeInfo ...
|
||||||
|
type TypeInfo struct { |
||||||
|
rt reflect.Type |
||||||
|
|
||||||
|
fields []TypeInfoField |
||||||
|
} |
||||||
|
|
||||||
|
// Type ...
|
||||||
|
func (ti *TypeInfo) Type() reflect.Type { |
||||||
|
return ti.rt |
||||||
|
} |
||||||
|
|
||||||
|
// Kind ...
|
||||||
|
func (ti *TypeInfo) Kind() reflect.Kind { |
||||||
|
return ti.rt.Kind() |
||||||
|
} |
||||||
|
|
||||||
|
// TypeInfoField ...
|
||||||
|
type TypeInfoField struct { |
||||||
|
sf reflect.StructField |
||||||
|
tags *structtag.Tags |
||||||
|
|
||||||
|
Name string |
||||||
|
} |
||||||
|
|
||||||
|
// Type ...
|
||||||
|
func (tif *TypeInfoField) Type() reflect.Type { |
||||||
|
return tif.sf.Type |
||||||
|
} |
||||||
|
|
||||||
|
// Kind ...
|
||||||
|
func (tif *TypeInfoField) Kind() reflect.Kind { |
||||||
|
return tif.sf.Type.Kind() |
||||||
|
} |
||||||
|
|
||||||
|
// Tag ...
|
||||||
|
func (tif *TypeInfoField) Tag(key string) (*structtag.Tag, bool) { |
||||||
|
if tif.tags != nil { |
||||||
|
tag, _ := tif.tags.Get(key) |
||||||
|
if tag != nil { |
||||||
|
return tag, true |
||||||
|
} |
||||||
|
} |
||||||
|
return nil, false |
||||||
|
} |
||||||
|
|
||||||
|
// NewTypeInfo ...
|
||||||
|
func NewTypeInfo(rt reflect.Type) (TypeInfo, error) { |
||||||
|
log.Printf("%s.%s: %s (%s)", "reflection", "NewTypeInfo", rt, rt.Kind()) |
||||||
|
|
||||||
|
ti := TypeInfo{ |
||||||
|
rt: rt, |
||||||
|
} |
||||||
|
|
||||||
|
err := ti.init() |
||||||
|
return ti, err |
||||||
|
} |
||||||
|
|
||||||
|
func (ti *TypeInfo) init() error { |
||||||
|
switch ti.Kind() { |
||||||
|
case reflect.Struct: |
||||||
|
return ti.initStruct() |
||||||
|
default: |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (ti *TypeInfo) initStruct() error { |
||||||
|
// load fields
|
||||||
|
n := ti.rt.NumField() |
||||||
|
fields := make([]TypeInfoField, 0, n) |
||||||
|
for i := 0; i < n; i++ { |
||||||
|
sf := ti.rt.Field(i) |
||||||
|
tags, err := structtag.Parse(string(sf.Tag)) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
// tag parse error
|
||||||
|
err = &UnmarshalTypeError{ |
||||||
|
Type: ti.rt, |
||||||
|
Err: errors.Wrap(err, structFieldName(sf)), |
||||||
|
} |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
if sf.IsExported() { |
||||||
|
log.Printf("%s.%s: [%v]: %q %s (%s)", |
||||||
|
"reflection", "NewTypeInfo", |
||||||
|
i, structFieldName(sf), sf.Type, sf.Type.Kind()) |
||||||
|
|
||||||
|
fields = append(fields, TypeInfoField{ |
||||||
|
sf: sf, |
||||||
|
tags: tags, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
ti.fields = fields |
||||||
|
return nil |
||||||
|
} |
Loading…
Reference in new issue