Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: simplify parsing numbers with overflow #3610

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/mapping/unmarshaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
105 changes: 25 additions & 80 deletions core/mapping/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
leftSquareBracket = '['
rightSquareBracket = ']'
segmentSeparator = ','
intSize = 32 << (^uint(0) >> 63)
)

var (
Expand All @@ -42,10 +43,6 @@ var (
)

type (
integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}

optionsCacheValue struct {
key string
options *fieldOptions
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 '[':
Expand All @@ -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()))
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down