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 |
||||
|
||||
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 |
||||
} |
||||
|
||||
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