github.com/qiniu/dyn@v1.3.0/dyn/dyn.go (about) 1 package dyn 2 3 import ( 4 "reflect" 5 "strconv" 6 "strings" 7 8 "github.com/qiniu/x/log" 9 ) 10 11 // ---------------------------------------------------------- 12 13 func TagName(tag string) string { 14 if idx := strings.Index(tag, ","); idx != -1 { 15 return tag[:idx] 16 } 17 return tag 18 } 19 20 func FieldByTag(cate string, sv reflect.Value, tagName string) (v reflect.Value) { 21 22 st := sv.Type() 23 for i := 0; i < sv.NumField(); i++ { 24 sf := st.Field(i) 25 tag := sf.Tag.Get(cate) 26 if tag == "" { 27 if sf.Name == tagName { 28 v = sv.Field(i) 29 return 30 } 31 } else if TagName(tag) == tagName { 32 v = sv.Field(i) 33 return 34 } 35 } 36 return 37 } 38 39 // ---------------------------------------------------------- 40 41 func GetVal(cate string, data reflect.Value, key string) (v reflect.Value, ok bool) { 42 43 parts := strings.Split(key, ".") 44 45 for _, part := range parts { 46 retry: 47 kind := data.Kind() 48 switch kind { 49 case reflect.Ptr, reflect.Interface: 50 data = data.Elem() 51 goto retry 52 case reflect.Struct: 53 v = FieldByTag(cate, data, part) 54 case reflect.Map: 55 v = data.MapIndex(reflect.ValueOf(part)) 56 case reflect.Array, reflect.Slice: 57 index, err := strconv.Atoi(part) 58 if err != nil { 59 log.Warn("GetVal failed: invalid index -", part) 60 return 61 } 62 if index >= data.Len() { 63 return 64 } 65 v = data.Index(index) 66 case reflect.Func: 67 out := data.Call(nil) 68 if len(out) != 1 { 69 log.Warn("GetVal failed: unsupport type -", data.Type(), ", key:", part) 70 return 71 } 72 data = out[0] 73 log.Debug("deref:", data.Interface(), part) 74 goto retry 75 case reflect.Invalid: 76 return 77 default: 78 log.Warn("GetVal failed: unsupported type -", kind, data.Type(), ", key:", part) 79 return 80 } 81 if !v.IsValid() { 82 return 83 } 84 data = v 85 } 86 ok = true 87 return 88 } 89 90 // ---------------------------------------------------------- 91 92 func Get(data interface{}, key string) (v interface{}, ok bool) { 93 94 val, ok := GetVal("json", reflect.ValueOf(data), key) 95 if ok { 96 v = val.Interface() 97 } 98 return 99 } 100 101 // ---------------------------------------------------------- 102 103 func Int(data interface{}) (val int64, ok bool) { 104 105 retry: 106 switch v := data.(type) { 107 case int: 108 val = int64(v) 109 case uint: 110 val = int64(v) 111 case int64: 112 val = v 113 case uint64: 114 val = int64(v) 115 case uintptr: 116 val = int64(v) 117 case int32: 118 val = int64(v) 119 case uint32: 120 val = int64(v) 121 case int16: 122 val = int64(v) 123 case uint16: 124 val = int64(v) 125 case uint8: 126 val = int64(v) 127 case int8: 128 val = int64(v) 129 case func() interface{}: 130 data = v() 131 goto retry 132 default: 133 return 134 } 135 ok = true 136 return 137 } 138 139 func GetInt(data interface{}, key string) (val int64, ok bool) { 140 141 v, ok := Get(data, key) 142 if ok { 143 val, ok = Int(v) 144 } 145 return 146 } 147 148 // ---------------------------------------------------------- 149 150 func Float(data interface{}) (val float64, ok bool) { 151 152 retry: 153 switch v := data.(type) { 154 case float64: 155 val = v 156 case float32: 157 val = float64(v) 158 case func() interface{}: 159 data = v() 160 goto retry 161 default: 162 v2, ok2 := Int(data) 163 if !ok2 { 164 return 165 } 166 val = float64(v2) 167 } 168 ok = true 169 return 170 } 171 172 func GetFloat(data interface{}, key string) (val float64, ok bool) { 173 174 v, ok := Get(data, key) 175 if ok { 176 val, ok = Float(v) 177 } 178 return 179 } 180 181 // ---------------------------------------------------------- 182 183 func String(data interface{}) (val string, ok bool) { 184 185 retry: 186 switch v := data.(type) { 187 case string: 188 val = v 189 case func() interface{}: 190 data = v() 191 goto retry 192 default: 193 return 194 } 195 ok = true 196 return 197 } 198 199 func GetString(data interface{}, key string) (val string, ok bool) { 200 201 v, ok := Get(data, key) 202 if ok { 203 val, ok = String(v) 204 } 205 return 206 } 207 208 // ----------------------------------------------------------