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 }