Skip to content

Commit

Permalink
✨ feat: enhance the convert func, support handle ptr type value
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Jan 4, 2024
1 parent 154fd5b commit 3ace818
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 3 deletions.
12 changes: 9 additions & 3 deletions internal/comfunc/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ type ConvOption struct {
// if ture: value is nil, will return convert error;
// if false(default): value is nil, will convert to zero value
NilAsFail bool
// EnablePtr auto convert ptr type(int,float,string) value. eg: *int to int
// HandlePtr auto convert ptr type(int,float,string) value. eg: *int to int
// - if true: will use real type try convert. default is false
EnablePtr bool
// - NOTE: current T type's ptr is default support.
HandlePtr bool
// set custom fallback convert func for not supported type.
UserConvFn comdef.ToStringFunc
}
Expand All @@ -85,6 +86,11 @@ var StrBySprintFn = func(v any) (string, error) {
return fmt.Sprint(v), nil
}

// WithHandlePtr set ConvOption.HandlePtr option
func WithHandlePtr(opt *ConvOption) {
opt.HandlePtr = true
}

// WithUserConvFn set ConvOption.UserConvFn option
func WithUserConvFn(fn comdef.ToStringFunc) ConvOptionFn {
return func(opt *ConvOption) {
Expand Down Expand Up @@ -155,7 +161,7 @@ func ToStringWith(in any, optFns ...ConvOptionFn) (str string, err error) {
case error:
str = value.Error()
default:
if opt.EnablePtr {
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
Expand Down
66 changes: 66 additions & 0 deletions mathutil/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package mathutil
import (
"fmt"
"math"
"reflect"
"strconv"
"strings"
"time"

"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/internal/checkfn"
"github.com/gookit/goutil/internal/comfunc"
)

Expand All @@ -34,6 +36,10 @@ type ConvOption[T any] struct {
// if ture: value is nil, will return convert error;
// if false(default): value is nil, will convert to zero value
NilAsFail bool
// HandlePtr auto convert ptr type(int,float,string) value. eg: *int to int
// - if true: will use real type try convert. default is false
// - NOTE: current T type's ptr is default support.
HandlePtr bool
// set custom fallback convert func for not supported type.
UserConvFn ToTypeFunc[T]
}
Expand Down Expand Up @@ -66,6 +72,11 @@ func WithNilAsFail[T any](opt *ConvOption[T]) {
opt.NilAsFail = true
}

// WithHandlePtr set ConvOption.HandlePtr option
func WithHandlePtr[T any](opt *ConvOption[T]) {
opt.HandlePtr = true
}

// WithUserConvFn set ConvOption.UserConvFn option
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
return func(opt *ConvOption[T]) {
Expand Down Expand Up @@ -134,6 +145,8 @@ func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
switch tVal := in.(type) {
case int:
iVal = tVal
case *int: // default support int ptr type
iVal = *tVal
case int8:
iVal = int(tVal)
case int16:
Expand Down Expand Up @@ -190,6 +203,15 @@ func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
}
}
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToIntWith(rv.Interface(), optFns...)
}
}
}

if opt.UserConvFn != nil {
return opt.UserConvFn(in)
}
Expand Down Expand Up @@ -276,6 +298,8 @@ func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
i64 = int64(tVal)
case int64:
i64 = tVal
case *int64: // default support int64 ptr type
i64 = *tVal
case uint:
i64 = int64(tVal)
case uint8:
Expand All @@ -295,6 +319,15 @@ func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
case comdef.Int64able: // eg: json.Number
i64, err = tVal.Int64()
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToInt64With(rv.Interface(), optFns...)
}
}
}

if opt.UserConvFn != nil {
i64, err = opt.UserConvFn(in)
} else {
Expand Down Expand Up @@ -367,6 +400,8 @@ func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
uVal = uint(tVal)
case uint:
uVal = tVal
case *uint: // default support uint ptr type
uVal = *tVal
case uint8:
uVal = uint(tVal)
case uint16:
Expand All @@ -390,6 +425,15 @@ func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
uVal = uint(u64)
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToUintWith(rv.Interface(), optFns...)
}
}
}

if opt.UserConvFn != nil {
uVal, err = opt.UserConvFn(in)
} else {
Expand Down Expand Up @@ -470,6 +514,8 @@ func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error
u64 = uint64(tVal)
case uint64:
u64 = tVal
case *uint64: // default support uint64 ptr type
u64 = *tVal
case float32:
u64 = uint64(tVal)
case float64:
Expand All @@ -483,6 +529,15 @@ func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error
case string:
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToUint64With(rv.Interface(), optFns...)
}
}
}

if opt.UserConvFn != nil {
u64, err = opt.UserConvFn(in)
} else {
Expand Down Expand Up @@ -572,11 +627,22 @@ func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err erro
f64 = float64(tVal)
case float64:
f64 = tVal
case *float64: // default support float64 ptr type
f64 = *tVal
case time.Duration:
f64 = float64(tVal)
case comdef.Float64able: // eg: json.Number
f64, err = tVal.Float64()
default:
if opt.HandlePtr {
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
rv = rv.Elem()
if checkfn.IsSimpleKind(rv.Kind()) {
return ToFloatWith(rv.Interface(), optFns...)
}
}
}

if opt.UserConvFn != nil {
f64, err = opt.UserConvFn(in)
} else {
Expand Down
98 changes: 98 additions & 0 deletions mathutil/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,104 @@ func TestWithNilAsFail(t *testing.T) {
is.Err(err)
}

func TestWithHandlePtr(t *testing.T) {
var err error
is := assert.New(t)

iv1 := 2
i641 := int64(2)

// int
t.Run("to int", func(t *testing.T) {
var iv int
iv, err = mathutil.ToIntWith(&iv1)
is.NoErr(err)
is.Eq(2, iv)

_, err = mathutil.ToIntWith(&i641)
is.Err(err)
iv, err = mathutil.ToIntWith(&i641, mathutil.WithHandlePtr[int])
is.NoErr(err)
is.Eq(2, iv)
})

// int64
t.Run("to int64", func(t *testing.T) {
var i64 int64
i64, err = mathutil.ToInt64With(&i641)
is.NoErr(err)
is.Eq(int64(2), i64)

_, err = mathutil.ToInt64With(&iv1)
is.Err(err)
i64, err = mathutil.ToInt64With(&iv1, mathutil.WithHandlePtr[int64])
is.NoErr(err)
is.Eq(int64(2), i64)
})

// uint
t.Run("to uint", func(t *testing.T) {
var u uint
u1 := uint(2)
u, err = mathutil.ToUintWith(&u1)
is.NoErr(err)
is.Eq(uint(2), u)

_, err = mathutil.ToUintWith(&iv1)
is.Err(err)
u, err = mathutil.ToUintWith(&iv1, mathutil.WithHandlePtr[uint])
is.NoErr(err)
is.Eq(uint(2), u)
})

// uint64
t.Run("to uint64", func(t *testing.T) {
var u64 uint64
u641 := uint64(2)
u64, err = mathutil.ToUint64With(&u641)
is.NoErr(err)
is.Eq(uint64(2), u64)

_, err = mathutil.ToUint64With(&iv1)
is.Err(err)
u64, err = mathutil.ToUint64With(&iv1, mathutil.WithHandlePtr[uint64])
is.NoErr(err)
is.Eq(uint64(2), u64)
})

// float
t.Run("to float", func(t *testing.T) {
var f float64
f1 := float64(2)
f, err = mathutil.ToFloatWith(&f1)
is.NoErr(err)
is.Eq(float64(2), f)

_, err = mathutil.ToFloatWith(&iv1)
is.Err(err)
f, err = mathutil.ToFloatWith(&iv1, mathutil.WithHandlePtr[float64])
is.NoErr(err)
is.Eq(float64(2), f)
})

// string
t.Run("to string", func(t *testing.T) {
var s string
s1 := "2"
s, err = mathutil.ToStringWith(&s1)
is.NoErr(err)
is.Eq("2", s)

_, err = mathutil.ToStringWith(&iv1)
is.Err(err)
s, err = mathutil.ToStringWith(&iv1, func(opt *comfunc.ConvOption) {
opt.HandlePtr = true
})
is.NoErr(err)
is.Eq("2", s)
})
}

func TestToInt(t *testing.T) {
is := assert.New(t)

Expand Down

0 comments on commit 3ace818

Please sign in to comment.