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