304 lines
8.1 KiB
Go
304 lines
8.1 KiB
Go
package mathutil
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gookit/goutil/comdef"
|
|
"github.com/gookit/goutil/internal/checkfn"
|
|
"github.com/gookit/goutil/internal/comfunc"
|
|
)
|
|
|
|
// ConvOption convert options
|
|
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
|
|
// StrictMode for convert value. default is false
|
|
//
|
|
// TRUE:
|
|
// - to int: string, float will return error
|
|
StrictMode bool
|
|
// set custom fallback convert func for not supported type.
|
|
UserConvFn ToTypeFunc[T]
|
|
}
|
|
|
|
// NewConvOption create a new ConvOption
|
|
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T] {
|
|
opt := &ConvOption[T]{}
|
|
opt.WithOption(optFns...)
|
|
return opt
|
|
}
|
|
|
|
// WithOption set convert option
|
|
func (opt *ConvOption[T]) WithOption(optFns ...ConvOptionFn[T]) {
|
|
for _, fn := range optFns {
|
|
if fn != nil {
|
|
fn(opt)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ConvOptionFn convert option func
|
|
type ConvOptionFn[T any] func(opt *ConvOption[T])
|
|
|
|
// WithNilAsFail set ConvOption.NilAsFail option
|
|
//
|
|
// Example:
|
|
//
|
|
// ToIntWithFunc(val, mathutil.WithNilAsFail[int])
|
|
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 }
|
|
|
|
// WithStrictMode set ConvOption.StrictMode option
|
|
func WithStrictMode[T any](opt *ConvOption[T]) { opt.StrictMode = true }
|
|
|
|
// WithUserConvFn set ConvOption.UserConvFn option
|
|
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
|
|
return func(opt *ConvOption[T]) {
|
|
opt.UserConvFn = fn
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
* region Strict to int/uint
|
|
*************************************************************/
|
|
|
|
// StrictInt check the given value is an integer(intX,uintX), return the int64 value and true if success
|
|
func StrictInt(val any) (int64, bool) {
|
|
switch tVal := val.(type) {
|
|
case int:
|
|
return int64(tVal), true
|
|
case int8:
|
|
return int64(tVal), true
|
|
case int16:
|
|
return int64(tVal), true
|
|
case int32:
|
|
return int64(tVal), true
|
|
case int64:
|
|
return tVal, true
|
|
case uint:
|
|
return int64(tVal), true
|
|
case uint8:
|
|
return int64(tVal), true
|
|
case uint16:
|
|
return int64(tVal), true
|
|
case uint32:
|
|
return int64(tVal), true
|
|
case uint64:
|
|
return int64(tVal), true
|
|
case uintptr:
|
|
return int64(tVal), true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
|
|
// StrictUint strict check value is integer(intX,uintX) and convert to uint64.
|
|
func StrictUint(val any) (uint64, bool) {
|
|
switch tVal := val.(type) {
|
|
case int:
|
|
return uint64(tVal), true
|
|
case int8:
|
|
return uint64(tVal), true
|
|
case int16:
|
|
return uint64(tVal), true
|
|
case int32:
|
|
return uint64(tVal), true
|
|
case int64:
|
|
return uint64(tVal), true
|
|
case uint:
|
|
return uint64(tVal), true
|
|
case uint8:
|
|
return uint64(tVal), true
|
|
case uint16:
|
|
return uint64(tVal), true
|
|
case uint32:
|
|
return uint64(tVal), true
|
|
case uint64:
|
|
return tVal, true
|
|
case uintptr:
|
|
return uint64(tVal), true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
* region convert to float64
|
|
*************************************************************/
|
|
|
|
// QuietFloat convert value to float64, will ignore error. alias of SafeFloat
|
|
func QuietFloat(in any) float64 { return SafeFloat(in) }
|
|
|
|
// SafeFloat convert value to float64, will ignore error
|
|
func SafeFloat(in any) float64 {
|
|
val, _ := ToFloatWith(in)
|
|
return val
|
|
}
|
|
|
|
// FloatOrPanic convert value to float64, will panic on error
|
|
func FloatOrPanic(in any) float64 { return MustFloat(in) }
|
|
|
|
// MustFloat convert value to float64, will panic on error
|
|
func MustFloat(in any) float64 {
|
|
val, err := ToFloatWith(in)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return val
|
|
}
|
|
|
|
// FloatOrDefault convert value to float64, will return default value on error
|
|
func FloatOrDefault(in any, defVal float64) float64 { return FloatOr(in, defVal) }
|
|
|
|
// FloatOr convert value to float64, will return default value on error
|
|
func FloatOr(in any, defVal float64) float64 {
|
|
val, err := ToFloatWith(in)
|
|
if err != nil {
|
|
return defVal
|
|
}
|
|
return val
|
|
}
|
|
|
|
// Float convert value to float64, return error on failed
|
|
func Float(in any) (float64, error) { return ToFloatWith(in) }
|
|
|
|
// FloatOrErr convert value to float64, return error on failed
|
|
func FloatOrErr(in any) (float64, error) { return ToFloatWith(in) }
|
|
|
|
// ToFloat convert value to float64, return error on failed
|
|
func ToFloat(in any) (float64, error) { return ToFloatWith(in) }
|
|
|
|
// ToFloatWith try to convert value to float64. can with some option func, more see ConvOption.
|
|
func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err error) {
|
|
opt := NewConvOption(optFns...)
|
|
if !opt.NilAsFail && in == nil {
|
|
return 0, nil
|
|
}
|
|
|
|
switch tVal := in.(type) {
|
|
case string:
|
|
f64, err = strconv.ParseFloat(strings.TrimSpace(tVal), 64)
|
|
case int:
|
|
f64 = float64(tVal)
|
|
case int8:
|
|
f64 = float64(tVal)
|
|
case int16:
|
|
f64 = float64(tVal)
|
|
case int32:
|
|
f64 = float64(tVal)
|
|
case int64:
|
|
f64 = float64(tVal)
|
|
case uint:
|
|
f64 = float64(tVal)
|
|
case uint8:
|
|
f64 = float64(tVal)
|
|
case uint16:
|
|
f64 = float64(tVal)
|
|
case uint32:
|
|
f64 = float64(tVal)
|
|
case uint64:
|
|
f64 = float64(tVal)
|
|
case float32:
|
|
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 {
|
|
err = comdef.ErrConvType
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
/*************************************************************
|
|
* region intX/floatX to string
|
|
*************************************************************/
|
|
|
|
// MustString convert intX/floatX value to string, will panic on error
|
|
func MustString(val any) string {
|
|
str, err := ToStringWith(val)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return str
|
|
}
|
|
|
|
// StringOrPanic convert intX/floatX value to string, will panic on error
|
|
func StringOrPanic(val any) string { return MustString(val) }
|
|
|
|
// StringOrDefault convert intX/floatX value to string, will return default value on error
|
|
func StringOrDefault(val any, defVal string) string { return StringOr(val, defVal) }
|
|
|
|
// StringOr convert intX/floatX value to string, will return default value on error
|
|
func StringOr(val any, defVal string) string {
|
|
str, err := ToStringWith(val)
|
|
if err != nil {
|
|
return defVal
|
|
}
|
|
return str
|
|
}
|
|
|
|
// ToString convert intX/floatX value to string, return error on failed
|
|
func ToString(val any) (string, error) { return ToStringWith(val) }
|
|
|
|
// StringOrErr convert intX/floatX value to string, return error on failed
|
|
func StringOrErr(val any) (string, error) { return ToStringWith(val) }
|
|
|
|
// QuietString convert intX/floatX value to string, other type convert by fmt.Sprint
|
|
func QuietString(val any) string { return SafeString(val) }
|
|
|
|
// String convert intX/floatX value to string, other type convert by fmt.Sprint
|
|
func String(val any) string {
|
|
str, _ := TryToString(val, false)
|
|
return str
|
|
}
|
|
|
|
// SafeString convert intX/floatX value to string, other type convert by fmt.Sprint
|
|
func SafeString(val any) string {
|
|
str, _ := TryToString(val, false)
|
|
return str
|
|
}
|
|
|
|
// TryToString try convert intX/floatX value to string
|
|
//
|
|
// if defaultAsErr is False, will use fmt.Sprint convert other type
|
|
func TryToString(val any, defaultAsErr bool) (string, error) {
|
|
var optFn comfunc.ConvOptionFn
|
|
if !defaultAsErr {
|
|
optFn = comfunc.WithUserConvFn(comfunc.StrBySprintFn)
|
|
}
|
|
return ToStringWith(val, optFn)
|
|
}
|
|
|
|
// ToStringWith try to convert value to string. can with some option func, more see comfunc.ConvOption.
|
|
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error) {
|
|
return comfunc.ToStringWith(in, optFns...)
|
|
}
|