Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 161 lines (138 sloc) 3.929 kB
1876270 @ungerik initial files
authored
1 package utils
2
3 import (
4 "fmt"
5 "github.com/ungerik/go-start/errs"
6 "reflect"
7 "unicode"
8 )
9
10 type MatchStructFieldFunc func(field *reflect.StructField) bool
11
c47017e @ungerik utils.ExportedStructFields() and CopyExportedStructFields()
authored
12 func IsExportedName(name string) bool {
13 return name != "" && unicode.IsUpper(rune(name[0]))
14 }
15
1876270 @ungerik initial files
authored
16 func FindFlattenedStructField(t reflect.Type, matchFunc MatchStructFieldFunc) *reflect.StructField {
17 fieldCount := t.NumField()
18 for i := 0; i < fieldCount; i++ {
19 field := t.Field(i)
20 if unicode.IsUpper(rune(field.Name[0])) {
21 if field.Anonymous {
22 if field.Type.Kind() == reflect.Struct {
23 result := FindFlattenedStructField(field.Type, matchFunc)
24 if result != nil {
25 return result
26 }
27 }
28 } else {
29 if matchFunc(&field) {
30 return &field
31 }
32 }
33 }
34 }
35 return nil
36 }
37
38 // Creates a new zero valued instance of prototype
39 func NewInstance(prototype interface{}) interface{} {
40 t := reflect.TypeOf(prototype)
41 if t.Kind() == reflect.Ptr {
42 t = t.Elem()
43 }
44 return reflect.New(t).Interface()
45 }
46
47 func CallMethod(object interface{}, method string, args ...interface{}) (results []interface{}, err error) {
48 m := reflect.ValueOf(object).MethodByName(method)
49 if !m.IsValid() {
50 return nil, fmt.Errorf("%T has no method %s", object, method)
51 }
52
53 a := make([]reflect.Value, len(args))
54 for i, arg := range args {
55 a[i] = reflect.ValueOf(arg)
56 }
57
58 defer func() {
59 if r := recover(); r != nil {
60 err = errs.Format("utils.CallMethod() recovered from: %v", r)
61 }
62 }()
63 r := m.Call(a)
64
65 results = make([]interface{}, len(r))
66 for i, result := range r {
67 results[i] = result.Interface()
68 }
69 return results, nil
70 }
71
72 func CallMethod1(object interface{}, method string, args ...interface{}) (result interface{}, err error) {
73 results, err := CallMethod(object, method, args...)
74 if err != nil {
75 return
76 }
77 if len(results) != 1 {
78 return nil, fmt.Errorf("One result expected from method %s of %T, %d returned", method, object, len(results))
79 }
80 return results[0], nil
81 }
82
83 func IsDefaultValue(value interface{}) bool {
84 v := reflect.ValueOf(value)
85 switch v.Kind() {
86 case reflect.Ptr:
87 if v.IsNil() {
88 return true
89 }
90 return IsDefaultValue(v.Elem().Interface())
91
92 case reflect.String:
93 return v.String() == ""
94
95 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
96 return v.Int() == 0
97
98 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
99 return v.Uint() == 0
100
101 case reflect.Float32, reflect.Float64:
102 return v.Float() == 0
103
104 case reflect.Bool:
105 return v.Bool() == false
106
107 case reflect.Struct:
108 // todo when struct comparison works
109
110 case reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface:
111 return v.IsNil()
112 }
113
114 return false
115 }
116
117 // Non nil interfaces can wrap nil values. Comparing the interface to nil, won't return if the wrapped value is nil.
118 func IsDeepNil(i interface{}) bool {
119 if i == nil {
120 return true
121 }
122 v := reflect.ValueOf(i)
123 switch v.Kind() {
124 case reflect.Chan, reflect.Func, reflect.Map, reflect.Slice:
125 return v.IsNil()
126 case reflect.Ptr, reflect.Interface:
127 return v.IsNil() || IsDeepNil(v.Elem().Interface())
128 }
129 return false
130 }
c47017e @ungerik utils.ExportedStructFields() and CopyExportedStructFields()
authored
131
132 func ExportedStructFields(s interface{}) map[string]interface{} {
133 result := make(map[string]interface{})
134 v := reflect.ValueOf(s)
135 t := reflect.TypeOf(s)
136 for i := 0; i < t.NumField(); i++ {
137 field := t.Field(i)
138 if IsExportedName(field.Name) {
139 result[field.Name] = v.Field(i).Interface()
140 }
141 }
142 return result
143 }
144
145 func CopyExportedStructFields(src, dst interface{}) (copied int) {
146 vsrc := reflect.ValueOf(src)
147 vdst := reflect.ValueOf(dst)
148 tsrc := reflect.TypeOf(src)
149 for i := 0; i < tsrc.NumField(); i++ {
150 tsrcfield := tsrc.Field(i)
151 if IsExportedName(tsrcfield.Name) {
152 dstfield := vdst.FieldByName(tsrcfield.Name)
153 if dstfield.IsValid() && dstfield.CanSet() && tsrcfield.Type.AssignableTo(dstfield.Type()) {
154 dstfield.Set(vsrc.Field(i))
155 copied++
156 }
157 }
158 }
159 return copied
160 }
Something went wrong with that request. Please try again.