Skip to content

Commit

Permalink
chore: simplify parsing numbers with overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
kevwan committed Oct 9, 2023
1 parent ff230c4 commit 9777b18
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 81 deletions.
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

0 comments on commit 9777b18

Please sign in to comment.