github.com/lingyao2333/mo-zero@v1.4.1/core/mapping/utils.go (about)

     1  package mapping
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"reflect"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/lingyao2333/mo-zero/core/stringx"
    14  )
    15  
    16  const (
    17  	defaultOption      = "default"
    18  	inheritOption      = "inherit"
    19  	stringOption       = "string"
    20  	optionalOption     = "optional"
    21  	optionsOption      = "options"
    22  	rangeOption        = "range"
    23  	optionSeparator    = "|"
    24  	equalToken         = "="
    25  	escapeChar         = '\\'
    26  	leftBracket        = '('
    27  	rightBracket       = ')'
    28  	leftSquareBracket  = '['
    29  	rightSquareBracket = ']'
    30  	segmentSeparator   = ','
    31  )
    32  
    33  var (
    34  	errUnsupportedType  = errors.New("unsupported type on setting field value")
    35  	errNumberRange      = errors.New("wrong number range setting")
    36  	optionsCache        = make(map[string]optionsCacheValue)
    37  	cacheLock           sync.RWMutex
    38  	structRequiredCache = make(map[reflect.Type]requiredCacheValue)
    39  	structCacheLock     sync.RWMutex
    40  )
    41  
    42  type (
    43  	optionsCacheValue struct {
    44  		key     string
    45  		options *fieldOptions
    46  		err     error
    47  	}
    48  
    49  	requiredCacheValue struct {
    50  		required bool
    51  		err      error
    52  	}
    53  )
    54  
    55  // Deref dereferences a type, if pointer type, returns its element type.
    56  func Deref(t reflect.Type) reflect.Type {
    57  	if t.Kind() == reflect.Ptr {
    58  		t = t.Elem()
    59  	}
    60  
    61  	return t
    62  }
    63  
    64  // Repr returns the string representation of v.
    65  func Repr(v interface{}) string {
    66  	if v == nil {
    67  		return ""
    68  	}
    69  
    70  	// if func (v *Type) String() string, we can't use Elem()
    71  	switch vt := v.(type) {
    72  	case fmt.Stringer:
    73  		return vt.String()
    74  	}
    75  
    76  	val := reflect.ValueOf(v)
    77  	if val.Kind() == reflect.Ptr && !val.IsNil() {
    78  		val = val.Elem()
    79  	}
    80  
    81  	return reprOfValue(val)
    82  }
    83  
    84  // ValidatePtr validates v if it's a valid pointer.
    85  func ValidatePtr(v *reflect.Value) error {
    86  	// sequence is very important, IsNil must be called after checking Kind() with reflect.Ptr,
    87  	// panic otherwise
    88  	if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() {
    89  		return fmt.Errorf("not a valid pointer: %v", v)
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func convertType(kind reflect.Kind, str string) (interface{}, error) {
    96  	switch kind {
    97  	case reflect.Bool:
    98  		return str == "1" || strings.ToLower(str) == "true", nil
    99  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   100  		intValue, err := strconv.ParseInt(str, 10, 64)
   101  		if err != nil {
   102  			return 0, fmt.Errorf("the value %q cannot parsed as int", str)
   103  		}
   104  
   105  		return intValue, nil
   106  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   107  		uintValue, err := strconv.ParseUint(str, 10, 64)
   108  		if err != nil {
   109  			return 0, fmt.Errorf("the value %q cannot parsed as uint", str)
   110  		}
   111  
   112  		return uintValue, nil
   113  	case reflect.Float32, reflect.Float64:
   114  		floatValue, err := strconv.ParseFloat(str, 64)
   115  		if err != nil {
   116  			return 0, fmt.Errorf("the value %q cannot parsed as float", str)
   117  		}
   118  
   119  		return floatValue, nil
   120  	case reflect.String:
   121  		return str, nil
   122  	default:
   123  		return nil, errUnsupportedType
   124  	}
   125  }
   126  
   127  func doParseKeyAndOptions(field reflect.StructField, value string) (string, *fieldOptions, error) {
   128  	segments := parseSegments(value)
   129  	key := strings.TrimSpace(segments[0])
   130  	options := segments[1:]
   131  
   132  	if len(options) == 0 {
   133  		return key, nil, nil
   134  	}
   135  
   136  	var fieldOpts fieldOptions
   137  	for _, segment := range options {
   138  		option := strings.TrimSpace(segment)
   139  		if err := parseOption(&fieldOpts, field.Name, option); err != nil {
   140  			return "", nil, err
   141  		}
   142  	}
   143  
   144  	return key, &fieldOpts, nil
   145  }
   146  
   147  // ensureValue ensures nested members not to be nil.
   148  // If pointer value is nil, set to a new value.
   149  func ensureValue(v reflect.Value) reflect.Value {
   150  	for {
   151  		if v.Kind() != reflect.Ptr {
   152  			break
   153  		}
   154  
   155  		if v.IsNil() {
   156  			v.Set(reflect.New(v.Type().Elem()))
   157  		}
   158  		v = v.Elem()
   159  	}
   160  
   161  	return v
   162  }
   163  
   164  func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
   165  	numFields := tp.NumField()
   166  	for i := 0; i < numFields; i++ {
   167  		childField := tp.Field(i)
   168  		if usingDifferentKeys(tag, childField) {
   169  			return true, nil
   170  		}
   171  
   172  		_, opts, err := parseKeyAndOptions(tag, childField)
   173  		if err != nil {
   174  			return false, err
   175  		}
   176  
   177  		if opts == nil {
   178  			if childField.Type.Kind() != reflect.Struct {
   179  				return true, nil
   180  			}
   181  
   182  			if required, err := implicitValueRequiredStruct(tag, childField.Type); err != nil {
   183  				return false, err
   184  			} else if required {
   185  				return true, nil
   186  			}
   187  		} else if !opts.Optional && len(opts.Default) == 0 {
   188  			return true, nil
   189  		} else if len(opts.OptionalDep) > 0 && opts.OptionalDep[0] == notSymbol {
   190  			return true, nil
   191  		}
   192  	}
   193  
   194  	return false, nil
   195  }
   196  
   197  func isLeftInclude(b byte) (bool, error) {
   198  	switch b {
   199  	case '[':
   200  		return true, nil
   201  	case '(':
   202  		return false, nil
   203  	default:
   204  		return false, errNumberRange
   205  	}
   206  }
   207  
   208  func isRightInclude(b byte) (bool, error) {
   209  	switch b {
   210  	case ']':
   211  		return true, nil
   212  	case ')':
   213  		return false, nil
   214  	default:
   215  		return false, errNumberRange
   216  	}
   217  }
   218  
   219  func maybeNewValue(field reflect.StructField, value reflect.Value) {
   220  	if field.Type.Kind() == reflect.Ptr && value.IsNil() {
   221  		value.Set(reflect.New(value.Type().Elem()))
   222  	}
   223  }
   224  
   225  func parseGroupedSegments(val string) []string {
   226  	val = strings.TrimLeftFunc(val, func(r rune) bool {
   227  		return r == leftBracket || r == leftSquareBracket
   228  	})
   229  	val = strings.TrimRightFunc(val, func(r rune) bool {
   230  		return r == rightBracket || r == rightSquareBracket
   231  	})
   232  	return parseSegments(val)
   233  }
   234  
   235  // don't modify returned fieldOptions, it's cached and shared among different calls.
   236  func parseKeyAndOptions(tagName string, field reflect.StructField) (string, *fieldOptions, error) {
   237  	value := field.Tag.Get(tagName)
   238  	if len(value) == 0 {
   239  		return field.Name, nil, nil
   240  	}
   241  
   242  	cacheLock.RLock()
   243  	cache, ok := optionsCache[value]
   244  	cacheLock.RUnlock()
   245  	if ok {
   246  		return stringx.TakeOne(cache.key, field.Name), cache.options, cache.err
   247  	}
   248  
   249  	key, options, err := doParseKeyAndOptions(field, value)
   250  	cacheLock.Lock()
   251  	optionsCache[value] = optionsCacheValue{
   252  		key:     key,
   253  		options: options,
   254  		err:     err,
   255  	}
   256  	cacheLock.Unlock()
   257  
   258  	return stringx.TakeOne(key, field.Name), options, err
   259  }
   260  
   261  // support below notations:
   262  // [:5] (:5] [:5) (:5)
   263  // [1:] [1:) (1:] (1:)
   264  // [1:5] [1:5) (1:5] (1:5)
   265  func parseNumberRange(str string) (*numberRange, error) {
   266  	if len(str) == 0 {
   267  		return nil, errNumberRange
   268  	}
   269  
   270  	leftInclude, err := isLeftInclude(str[0])
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	str = str[1:]
   276  	if len(str) == 0 {
   277  		return nil, errNumberRange
   278  	}
   279  
   280  	rightInclude, err := isRightInclude(str[len(str)-1])
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  
   285  	str = str[:len(str)-1]
   286  	fields := strings.Split(str, ":")
   287  	if len(fields) != 2 {
   288  		return nil, errNumberRange
   289  	}
   290  
   291  	if len(fields[0]) == 0 && len(fields[1]) == 0 {
   292  		return nil, errNumberRange
   293  	}
   294  
   295  	var left float64
   296  	if len(fields[0]) > 0 {
   297  		var err error
   298  		if left, err = strconv.ParseFloat(fields[0], 64); err != nil {
   299  			return nil, err
   300  		}
   301  	} else {
   302  		left = -math.MaxFloat64
   303  	}
   304  
   305  	var right float64
   306  	if len(fields[1]) > 0 {
   307  		var err error
   308  		if right, err = strconv.ParseFloat(fields[1], 64); err != nil {
   309  			return nil, err
   310  		}
   311  	} else {
   312  		right = math.MaxFloat64
   313  	}
   314  
   315  	if left > right {
   316  		return nil, errNumberRange
   317  	}
   318  
   319  	// [2:2] valid
   320  	// [2:2) invalid
   321  	// (2:2] invalid
   322  	// (2:2) invalid
   323  	if left == right {
   324  		if !leftInclude || !rightInclude {
   325  			return nil, errNumberRange
   326  		}
   327  	}
   328  
   329  	return &numberRange{
   330  		left:         left,
   331  		leftInclude:  leftInclude,
   332  		right:        right,
   333  		rightInclude: rightInclude,
   334  	}, nil
   335  }
   336  
   337  func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
   338  	switch {
   339  	case option == inheritOption:
   340  		fieldOpts.Inherit = true
   341  	case option == stringOption:
   342  		fieldOpts.FromString = true
   343  	case strings.HasPrefix(option, optionalOption):
   344  		segs := strings.Split(option, equalToken)
   345  		switch len(segs) {
   346  		case 1:
   347  			fieldOpts.Optional = true
   348  		case 2:
   349  			fieldOpts.Optional = true
   350  			fieldOpts.OptionalDep = segs[1]
   351  		default:
   352  			return fmt.Errorf("field %s has wrong optional", fieldName)
   353  		}
   354  	case option == optionalOption:
   355  		fieldOpts.Optional = true
   356  	case strings.HasPrefix(option, optionsOption):
   357  		segs := strings.Split(option, equalToken)
   358  		if len(segs) != 2 {
   359  			return fmt.Errorf("field %s has wrong options", fieldName)
   360  		}
   361  
   362  		fieldOpts.Options = parseOptions(segs[1])
   363  	case strings.HasPrefix(option, defaultOption):
   364  		segs := strings.Split(option, equalToken)
   365  		if len(segs) != 2 {
   366  			return fmt.Errorf("field %s has wrong default option", fieldName)
   367  		}
   368  
   369  		fieldOpts.Default = strings.TrimSpace(segs[1])
   370  	case strings.HasPrefix(option, rangeOption):
   371  		segs := strings.Split(option, equalToken)
   372  		if len(segs) != 2 {
   373  			return fmt.Errorf("field %s has wrong range", fieldName)
   374  		}
   375  
   376  		nr, err := parseNumberRange(segs[1])
   377  		if err != nil {
   378  			return err
   379  		}
   380  
   381  		fieldOpts.Range = nr
   382  	}
   383  
   384  	return nil
   385  }
   386  
   387  // parseOptions parses the given options in tag.
   388  // for example: `json:"name,options=foo|bar"` or `json:"name,options=[foo,bar]"`
   389  func parseOptions(val string) []string {
   390  	if len(val) == 0 {
   391  		return nil
   392  	}
   393  
   394  	if val[0] == leftSquareBracket {
   395  		return parseGroupedSegments(val)
   396  	}
   397  
   398  	return strings.Split(val, optionSeparator)
   399  }
   400  
   401  func parseSegments(val string) []string {
   402  	var segments []string
   403  	var escaped, grouped bool
   404  	var buf strings.Builder
   405  
   406  	for _, ch := range val {
   407  		if escaped {
   408  			buf.WriteRune(ch)
   409  			escaped = false
   410  			continue
   411  		}
   412  
   413  		switch ch {
   414  		case segmentSeparator:
   415  			if grouped {
   416  				buf.WriteRune(ch)
   417  			} else {
   418  				// need to trim spaces, but we cannot ignore empty string,
   419  				// because the first segment stands for the key might be empty.
   420  				// if ignored, the later tag will be used as the key.
   421  				segments = append(segments, strings.TrimSpace(buf.String()))
   422  				buf.Reset()
   423  			}
   424  		case escapeChar:
   425  			if grouped {
   426  				buf.WriteRune(ch)
   427  			} else {
   428  				escaped = true
   429  			}
   430  		case leftBracket, leftSquareBracket:
   431  			buf.WriteRune(ch)
   432  			grouped = true
   433  		case rightBracket, rightSquareBracket:
   434  			buf.WriteRune(ch)
   435  			grouped = false
   436  		default:
   437  			buf.WriteRune(ch)
   438  		}
   439  	}
   440  
   441  	last := strings.TrimSpace(buf.String())
   442  	// ignore last empty string
   443  	if len(last) > 0 {
   444  		segments = append(segments, last)
   445  	}
   446  
   447  	return segments
   448  }
   449  
   450  func reprOfValue(val reflect.Value) string {
   451  	switch vt := val.Interface().(type) {
   452  	case bool:
   453  		return strconv.FormatBool(vt)
   454  	case error:
   455  		return vt.Error()
   456  	case float32:
   457  		return strconv.FormatFloat(float64(vt), 'f', -1, 32)
   458  	case float64:
   459  		return strconv.FormatFloat(vt, 'f', -1, 64)
   460  	case fmt.Stringer:
   461  		return vt.String()
   462  	case int:
   463  		return strconv.Itoa(vt)
   464  	case int8:
   465  		return strconv.Itoa(int(vt))
   466  	case int16:
   467  		return strconv.Itoa(int(vt))
   468  	case int32:
   469  		return strconv.Itoa(int(vt))
   470  	case int64:
   471  		return strconv.FormatInt(vt, 10)
   472  	case string:
   473  		return vt
   474  	case uint:
   475  		return strconv.FormatUint(uint64(vt), 10)
   476  	case uint8:
   477  		return strconv.FormatUint(uint64(vt), 10)
   478  	case uint16:
   479  		return strconv.FormatUint(uint64(vt), 10)
   480  	case uint32:
   481  		return strconv.FormatUint(uint64(vt), 10)
   482  	case uint64:
   483  		return strconv.FormatUint(vt, 10)
   484  	case []byte:
   485  		return string(vt)
   486  	default:
   487  		return fmt.Sprint(val.Interface())
   488  	}
   489  }
   490  
   491  func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v interface{}) error {
   492  	switch kind {
   493  	case reflect.Bool:
   494  		value.SetBool(v.(bool))
   495  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   496  		value.SetInt(v.(int64))
   497  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   498  		value.SetUint(v.(uint64))
   499  	case reflect.Float32, reflect.Float64:
   500  		value.SetFloat(v.(float64))
   501  	case reflect.String:
   502  		value.SetString(v.(string))
   503  	default:
   504  		return errUnsupportedType
   505  	}
   506  
   507  	return nil
   508  }
   509  
   510  func setValue(kind reflect.Kind, value reflect.Value, str string) error {
   511  	if !value.CanSet() {
   512  		return errValueNotSettable
   513  	}
   514  
   515  	value = ensureValue(value)
   516  	v, err := convertType(kind, str)
   517  	if err != nil {
   518  		return err
   519  	}
   520  
   521  	return setMatchedPrimitiveValue(kind, value, v)
   522  }
   523  
   524  func structValueRequired(tag string, tp reflect.Type) (bool, error) {
   525  	structCacheLock.RLock()
   526  	val, ok := structRequiredCache[tp]
   527  	structCacheLock.RUnlock()
   528  	if ok {
   529  		return val.required, val.err
   530  	}
   531  
   532  	required, err := implicitValueRequiredStruct(tag, tp)
   533  	structCacheLock.Lock()
   534  	structRequiredCache[tp] = requiredCacheValue{
   535  		required: required,
   536  		err:      err,
   537  	}
   538  	structCacheLock.Unlock()
   539  
   540  	return required, err
   541  }
   542  
   543  func toFloat64(v interface{}) (float64, bool) {
   544  	switch val := v.(type) {
   545  	case int:
   546  		return float64(val), true
   547  	case int8:
   548  		return float64(val), true
   549  	case int16:
   550  		return float64(val), true
   551  	case int32:
   552  		return float64(val), true
   553  	case int64:
   554  		return float64(val), true
   555  	case uint:
   556  		return float64(val), true
   557  	case uint8:
   558  		return float64(val), true
   559  	case uint16:
   560  		return float64(val), true
   561  	case uint32:
   562  		return float64(val), true
   563  	case uint64:
   564  		return float64(val), true
   565  	case float32:
   566  		return float64(val), true
   567  	case float64:
   568  		return val, true
   569  	default:
   570  		return 0, false
   571  	}
   572  }
   573  
   574  func usingDifferentKeys(key string, field reflect.StructField) bool {
   575  	if len(field.Tag) > 0 {
   576  		if _, ok := field.Tag.Lookup(key); !ok {
   577  			return true
   578  		}
   579  	}
   580  
   581  	return false
   582  }
   583  
   584  func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string, opts *fieldOptionsWithContext) error {
   585  	if !value.CanSet() {
   586  		return errValueNotSettable
   587  	}
   588  
   589  	v, err := convertType(kind, str)
   590  	if err != nil {
   591  		return err
   592  	}
   593  
   594  	if err := validateValueRange(v, opts); err != nil {
   595  		return err
   596  	}
   597  
   598  	return setMatchedPrimitiveValue(kind, value, v)
   599  }
   600  
   601  func validateJsonNumberRange(v json.Number, opts *fieldOptionsWithContext) error {
   602  	if opts == nil || opts.Range == nil {
   603  		return nil
   604  	}
   605  
   606  	fv, err := v.Float64()
   607  	if err != nil {
   608  		return err
   609  	}
   610  
   611  	return validateNumberRange(fv, opts.Range)
   612  }
   613  
   614  func validateNumberRange(fv float64, nr *numberRange) error {
   615  	if nr == nil {
   616  		return nil
   617  	}
   618  
   619  	if (nr.leftInclude && fv < nr.left) || (!nr.leftInclude && fv <= nr.left) {
   620  		return errNumberRange
   621  	}
   622  
   623  	if (nr.rightInclude && fv > nr.right) || (!nr.rightInclude && fv >= nr.right) {
   624  		return errNumberRange
   625  	}
   626  
   627  	return nil
   628  }
   629  
   630  func validateValueInOptions(val interface{}, options []string) error {
   631  	if len(options) > 0 {
   632  		switch v := val.(type) {
   633  		case string:
   634  			if !stringx.Contains(options, v) {
   635  				return fmt.Errorf(`error: value "%s" is not defined in options "%v"`, v, options)
   636  			}
   637  		default:
   638  			if !stringx.Contains(options, Repr(v)) {
   639  				return fmt.Errorf(`error: value "%v" is not defined in options "%v"`, val, options)
   640  			}
   641  		}
   642  	}
   643  
   644  	return nil
   645  }
   646  
   647  func validateValueRange(mapValue interface{}, opts *fieldOptionsWithContext) error {
   648  	if opts == nil || opts.Range == nil {
   649  		return nil
   650  	}
   651  
   652  	fv, ok := toFloat64(mapValue)
   653  	if !ok {
   654  		return errNumberRange
   655  	}
   656  
   657  	return validateNumberRange(fv, opts.Range)
   658  }