Procházet zdrojové kódy

chore: simplify parsing numbers with overflow (#3610)

Kevin Wan před 1 rokem
rodič
revize
5aedd9c076
2 změnil soubory, kde provedl 26 přidání a 81 odebrání
  1. 1 1
      core/mapping/unmarshaler.go
  2. 25 80
      core/mapping/utils.go

+ 1 - 1
core/mapping/unmarshaler.go

@@ -622,7 +622,7 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
 		}
 
 		if fValue > math.MaxFloat32 {
-			return float32OverflowError(v.String())
+			return fmt.Errorf("parsing %q as float32: value out of range", v.String())
 		}
 
 		target.SetFloat(fValue)

+ 25 - 80
core/mapping/utils.go

@@ -30,6 +30,7 @@ const (
 	leftSquareBracket  = '['
 	rightSquareBracket = ']'
 	segmentSeparator   = ','
+	intSize            = 32 << (^uint(0) >> 63)
 )
 
 var (
@@ -42,10 +43,6 @@ var (
 )
 
 type (
-	integer interface {
-		~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
-	}
-
 	optionsCacheValue struct {
 		key     string
 		options *fieldOptions
@@ -104,38 +101,30 @@ func convertTypeFromString(kind reflect.Kind, str string) (any, error) {
 		default:
 			return false, errTypeMismatch
 		}
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		intValue, err := strconv.ParseInt(str, 10, 64)
-		if err != nil {
-			return 0, err
-		}
-
-		return intValue, nil
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		uintValue, err := strconv.ParseUint(str, 10, 64)
-		if err != nil {
-			return 0, err
-		}
-
-		return uintValue, nil
+	case reflect.Int:
+		return strconv.ParseInt(str, 10, intSize)
+	case reflect.Int8:
+		return strconv.ParseInt(str, 10, 8)
+	case reflect.Int16:
+		return strconv.ParseInt(str, 10, 16)
+	case reflect.Int32:
+		return strconv.ParseInt(str, 10, 32)
+	case reflect.Int64:
+		return strconv.ParseInt(str, 10, 64)
+	case reflect.Uint:
+		return strconv.ParseUint(str, 10, intSize)
+	case reflect.Uint8:
+		return strconv.ParseUint(str, 10, 8)
+	case reflect.Uint16:
+		return strconv.ParseUint(str, 10, 16)
+	case reflect.Uint32:
+		return strconv.ParseUint(str, 10, 32)
+	case reflect.Uint64:
+		return strconv.ParseUint(str, 10, 64)
 	case reflect.Float32:
-		floatValue, err := strconv.ParseFloat(str, 64)
-		if err != nil {
-			return 0, err
-		}
-
-		if floatValue > math.MaxFloat32 {
-			return 0, float32OverflowError(str)
-		}
-
-		return floatValue, nil
+		return strconv.ParseFloat(str, 32)
 	case reflect.Float64:
-		floatValue, err := strconv.ParseFloat(str, 64)
-		if err != nil {
-			return 0, err
-		}
-
-		return floatValue, nil
+		return strconv.ParseFloat(str, 64)
 	case reflect.String:
 		return str, nil
 	default:
@@ -230,10 +219,6 @@ func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
 	return false, nil
 }
 
-func intOverflowError[T integer](v T, kind reflect.Kind) error {
-	return fmt.Errorf("parsing \"%d\" as %s: value out of range", v, kind.String())
-}
-
 func isLeftInclude(b byte) (bool, error) {
 	switch b {
 	case '[':
@@ -256,10 +241,6 @@ func isRightInclude(b byte) (bool, error) {
 	}
 }
 
-func float32OverflowError(str string) error {
-	return fmt.Errorf("parsing %q as float32: value out of range", str)
-}
-
 func maybeNewValue(fieldType reflect.Type, value reflect.Value) {
 	if fieldType.Kind() == reflect.Ptr && value.IsNil() {
 		value.Set(reflect.New(value.Type().Elem()))
@@ -505,41 +486,15 @@ func parseSegments(val string) []string {
 	return segments
 }
 
-func setIntValue(value reflect.Value, v any, min, max int64) error {
-	iv := v.(int64)
-	if iv < min || iv > max {
-		return intOverflowError(iv, value.Kind())
-	}
-
-	value.SetInt(iv)
-	return nil
-}
-
 func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) error {
 	switch kind {
 	case reflect.Bool:
 		value.SetBool(v.(bool))
 		return nil
-	case reflect.Int: // int depends on int size, 32 or 64
-		return setIntValue(value, v, math.MinInt, math.MaxInt)
-	case reflect.Int8:
-		return setIntValue(value, v, math.MinInt8, math.MaxInt8)
-	case reflect.Int16:
-		return setIntValue(value, v, math.MinInt16, math.MaxInt16)
-	case reflect.Int32:
-		return setIntValue(value, v, math.MinInt32, math.MaxInt32)
-	case reflect.Int64:
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		value.SetInt(v.(int64))
 		return nil
-	case reflect.Uint: // uint depends on int size, 32 or 64
-		return setUintValue(value, v, math.MaxUint)
-	case reflect.Uint8:
-		return setUintValue(value, v, math.MaxUint8)
-	case reflect.Uint16:
-		return setUintValue(value, v, math.MaxUint16)
-	case reflect.Uint32:
-		return setUintValue(value, v, math.MaxUint32)
-	case reflect.Uint64:
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 		value.SetUint(v.(uint64))
 		return nil
 	case reflect.Float32, reflect.Float64:
@@ -553,16 +508,6 @@ func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) err
 	}
 }
 
-func setUintValue(value reflect.Value, v any, boundary uint64) error {
-	iv := v.(uint64)
-	if iv > boundary {
-		return intOverflowError(iv, value.Kind())
-	}
-
-	value.SetUint(iv)
-	return nil
-}
-
 func setValueFromString(kind reflect.Kind, value reflect.Value, str string) error {
 	if !value.CanSet() {
 		return errValueNotSettable