Files
opencloud/vendor/github.com/gookit/goutil/mathutil/conv2int.go
PC Kitty d97217f22c Update github.com/gookit/goutil to v0.7.4 for FreeBSD compatibility
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
2026-04-28 18:03:17 +02:00

649 lines
15 KiB
Go

package mathutil
import (
"fmt"
"math"
"reflect"
"strconv"
"strings"
"time"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/internal/checkfn"
)
/*************************************************************
* region convert to int
*************************************************************/
// Int convert value to int
func Int(in any) (int, error) { return ToInt(in) }
// SafeInt convert value to int, will ignore error
func SafeInt(in any) int {
val, _ := ToInt(in)
return val
}
// QuietInt convert value to int, will ignore error
func QuietInt(in any) int { return SafeInt(in) }
// IntOrPanic convert value to int, will panic on error
func IntOrPanic(in any) int {
val, err := ToInt(in)
if err != nil {
panic(err)
}
return val
}
// MustInt convert value to int, will panic on error
func MustInt(in any) int { return IntOrPanic(in) }
// IntOrDefault convert value to int, return defaultVal on failed
func IntOrDefault(in any, defVal int) int { return IntOr(in, defVal) }
// IntOr convert value to int, return defaultVal on failed
func IntOr(in any, defVal int) int {
val, err := ToIntWith(in)
if err != nil {
return defVal
}
return val
}
// IntOrErr convert value to int, return error on failed
func IntOrErr(in any) (int, error) { return ToIntWith(in) }
// ToInt convert value to int, return error on failed
func ToInt(in any) (int, error) { return ToIntWith(in) }
// ToIntWith convert value to int, can with some option func.
//
// Example:
//
// ToIntWithFunc(val, mathutil.WithNilAsFail, mathutil.WithUserConvFn(func(in any) (int, error) {
// })
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
if len(optFns) == 0 && in == nil {
return 0, nil
}
var opt *ConvOption[int]
if len(optFns) > 0 {
opt = NewConvOption(optFns...)
if in == nil && opt.NilAsFail {
err = comdef.ErrConvType
return
}
}
if tVal, ok := in.(string); ok {
// in strict mode, cannot convert string to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
// try convert to int
iVal, err = TryStrInt(tVal)
return
}
switch tVal := in.(type) {
case int:
iVal = tVal
case *int: // default support int ptr type
iVal = *tVal
case int8:
iVal = int(tVal)
case int16:
iVal = int(tVal)
case int32:
iVal = int(tVal)
case int64:
if tVal > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(tVal)
}
case uint:
if tVal > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(tVal)
}
case uint8:
iVal = int(tVal)
case uint16:
iVal = int(tVal)
case uint32:
if tVal > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(tVal)
}
case uint64:
if tVal > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(tVal)
}
case float32:
iVal = int(tVal)
case float64:
iVal = int(tVal)
case time.Duration:
if tVal > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(tVal)
}
case comdef.Int64able: // eg: json.Number
var i64 int64
if i64, err = tVal.Int64(); err == nil {
if i64 > math.MaxInt32 {
err = fmt.Errorf("value overflow int32. input: %v", tVal)
} else {
iVal = int(i64)
}
}
default:
if opt == nil {
err = comdef.ErrConvType
return
}
if opt.UserConvFn != nil {
iVal, err = opt.UserConvFn(in)
} else 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...)
}
}
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* region convert to int64
*************************************************************/
// Int64 convert value to int64, return error on failed
func Int64(in any) (int64, error) { return ToInt64(in) }
// SafeInt64 convert value to int64, will ignore error
func SafeInt64(in any) int64 {
i64, _ := ToInt64With(in)
return i64
}
// QuietInt64 convert value to int64, will ignore error
func QuietInt64(in any) int64 { return SafeInt64(in) }
// MustInt64 convert value to int64, will panic on error
func MustInt64(in any) int64 {
i64, err := ToInt64With(in)
if err != nil {
panic(err)
}
return i64
}
// Int64OrDefault convert value to int64, return default val on failed
func Int64OrDefault(in any, defVal int64) int64 { return Int64Or(in, defVal) }
// Int64Or convert value to int64, return default val on failed
func Int64Or(in any, defVal int64) int64 {
i64, err := ToInt64With(in)
if err != nil {
return defVal
}
return i64
}
// ToInt64 convert value to int64, return error on failed
func ToInt64(in any) (int64, error) { return ToInt64With(in) }
// Int64OrErr convert value to int64, return error on failed
func Int64OrErr(in any) (int64, error) { return ToInt64With(in) }
// ToInt64With try to convert value to int64. can with some option func, more see ConvOption.
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
if len(optFns) == 0 && in == nil {
return 0, nil
}
var opt *ConvOption[int64]
if len(optFns) > 0 {
opt = NewConvOption(optFns...)
if in == nil && opt.NilAsFail {
err = comdef.ErrConvType
return
}
}
if tVal, ok := in.(string); ok {
// in strict mode, cannot convert string to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
// try convert to int64
i64, err = TryStrInt64(tVal)
return
}
switch tVal := in.(type) {
case int:
i64 = int64(tVal)
case int8:
i64 = int64(tVal)
case int16:
i64 = int64(tVal)
case int32:
i64 = int64(tVal)
case int64:
i64 = tVal
case *int64: // default support int64 ptr type
i64 = *tVal
case uint:
i64 = int64(tVal)
case uint8:
i64 = int64(tVal)
case uint16:
i64 = int64(tVal)
case uint32:
i64 = int64(tVal)
case uint64:
i64 = int64(tVal)
case float32:
// in strict mode, cannot convert float to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
i64 = int64(tVal)
case float64:
// in strict mode, cannot convert float to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
if tVal > math.MaxInt64 {
err = comdef.ErrConvType
return
}
i64 = int64(tVal)
case time.Duration:
i64 = int64(tVal)
case comdef.Int64able: // eg: json.Number
i64, err = tVal.Int64()
default:
if opt == nil {
err = comdef.ErrConvType
return
}
if opt.UserConvFn != nil {
i64, err = opt.UserConvFn(in)
} else 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...)
}
}
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* region convert to uint
*************************************************************/
// Uint convert any to uint, return error on failed
func Uint(in any) (uint, error) { return ToUint(in) }
// SafeUint convert any to uint, will ignore error
func SafeUint(in any) uint {
val, _ := ToUint(in)
return val
}
// QuietUint convert any to uint, will ignore error
func QuietUint(in any) uint { return SafeUint(in) }
// MustUint convert any to uint, will panic on error
func MustUint(in any) uint {
val, err := ToUintWith(in)
if err != nil {
panic(err)
}
return val
}
// UintOrDefault convert any to uint, return default val on failed
func UintOrDefault(in any, defVal uint) uint { return UintOr(in, defVal) }
// UintOr convert any to uint, return default val on failed
func UintOr(in any, defVal uint) uint {
val, err := ToUintWith(in)
if err != nil {
return defVal
}
return val
}
// UintOrErr convert value to uint, return error on failed
func UintOrErr(in any) (uint, error) { return ToUintWith(in) }
// ToUint convert value to uint, return error on failed
func ToUint(in any) (u64 uint, err error) { return ToUintWith(in) }
// ToUintWith try to convert value to uint. can with some option func, more see ConvOption.
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
if len(optFns) == 0 && in == nil {
return 0, nil
}
var opt *ConvOption[uint]
if len(optFns) > 0 {
opt = NewConvOption(optFns...)
if in == nil && opt.NilAsFail {
err = comdef.ErrConvType
return
}
}
if tVal, ok := in.(string); ok {
// in strict mode, cannot convert string to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
// try convert to uint64
var u64 uint64
if u64, err = TryStrUint64(tVal); err == nil {
uVal = uint(u64)
}
return
}
switch tVal := in.(type) {
case int:
uVal = uint(tVal)
case int8:
uVal = uint(tVal)
case int16:
uVal = uint(tVal)
case int32:
uVal = uint(tVal)
case int64:
uVal = uint(tVal)
case uint:
uVal = tVal
case *uint: // default support uint ptr type
uVal = *tVal
case uint8:
uVal = uint(tVal)
case uint16:
uVal = uint(tVal)
case uint32:
uVal = uint(tVal)
case uint64:
uVal = uint(tVal)
case float32:
uVal = uint(tVal)
case float64:
uVal = uint(tVal)
case time.Duration:
uVal = uint(tVal)
case comdef.Int64able: // eg: json.Number
var i64 int64
i64, err = tVal.Int64()
uVal = uint(i64)
default:
if opt == nil {
err = comdef.ErrConvType
return
}
if opt.UserConvFn != nil {
uVal, err = opt.UserConvFn(in)
} else 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...)
}
}
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* region convert to uint64
*************************************************************/
// Uint64 convert any to uint64, return error on failed
func Uint64(in any) (uint64, error) { return ToUint64(in) }
// QuietUint64 convert any to uint64, will ignore error
func QuietUint64(in any) uint64 { return SafeUint64(in) }
// SafeUint64 convert any to uint64, will ignore error
func SafeUint64(in any) uint64 {
val, _ := ToUint64(in)
return val
}
// MustUint64 convert any to uint64, will panic on error
func MustUint64(in any) uint64 {
val, err := ToUint64With(in)
if err != nil {
panic(err)
}
return val
}
// Uint64OrDefault convert any to uint64, return default val on failed
func Uint64OrDefault(in any, defVal uint64) uint64 { return Uint64Or(in, defVal) }
// Uint64Or convert any to uint64, return default val on failed
func Uint64Or(in any, defVal uint64) uint64 {
val, err := ToUint64With(in)
if err != nil {
return defVal
}
return val
}
// Uint64OrErr convert value to uint64, return error on failed
func Uint64OrErr(in any) (uint64, error) { return ToUint64With(in) }
// ToUint64 convert value to uint64, return error on failed
func ToUint64(in any) (uint64, error) { return ToUint64With(in) }
// ToUint64With try to convert value to uint64. can with some option func, more see ConvOption.
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error) {
if len(optFns) == 0 && in == nil {
return 0, nil
}
var opt *ConvOption[uint64]
if len(optFns) > 0 {
opt = NewConvOption(optFns...)
if in == nil && opt.NilAsFail {
err = comdef.ErrConvType
return
}
}
if tVal, ok := in.(string); ok {
// in strict mode, cannot convert string to int
if opt != nil && opt.StrictMode {
err = comdef.ErrConvType
return
}
// try convert to uint64
u64, err = TryStrUint64(tVal)
return
}
switch tVal := in.(type) {
case int:
u64 = uint64(tVal)
case int8:
u64 = uint64(tVal)
case int16:
u64 = uint64(tVal)
case int32:
u64 = uint64(tVal)
case int64:
u64 = uint64(tVal)
case uint:
u64 = uint64(tVal)
case uint8:
u64 = uint64(tVal)
case uint16:
u64 = uint64(tVal)
case uint32:
u64 = uint64(tVal)
case uint64:
u64 = tVal
case *uint64: // default support uint64 ptr type
u64 = *tVal
case float32:
u64 = uint64(tVal)
case float64:
u64 = uint64(tVal)
case time.Duration:
u64 = uint64(tVal)
case comdef.Int64able: // eg: json.Number
var i64 int64
i64, err = tVal.Int64()
u64 = uint64(i64)
default:
if opt == nil {
err = comdef.ErrConvType
return
}
if opt.UserConvFn != nil {
u64, err = opt.UserConvFn(in)
} else 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...)
}
}
} else {
err = comdef.ErrConvType
}
}
return
}
/*************************************************************
* region string to intX/uintX
*************************************************************/
// StrInt convert string to int, ignore error
func StrInt(s string) int {
iVal, _ := strconv.Atoi(strings.TrimSpace(s))
return iVal
}
// StrIntOr convert string to int, return default val on failed
func StrIntOr(s string, defVal int) int {
iVal, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil {
return defVal
}
return iVal
}
// TryStrInt convert string to int, return error on failed.
//
// - empty string will return 0.
// - allow float string.
func TryStrInt(s string) (int, error) {
s = strings.TrimSpace(s)
if s == "" {
return 0, nil
}
// try convert to int
iVal, err := strconv.Atoi(s)
// handle the case where the string might be a float
if err != nil && checkfn.IsNumeric(s) {
var floatVal float64
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
iVal = int(math.Round(floatVal))
err = nil
}
}
return iVal, err
}
// TryStrInt64 convert string to int64, return error on failed.
//
// - empty string will return 0.
// - allow float string.
func TryStrInt64(s string) (int64, error) {
s = strings.TrimSpace(s)
if s == "" {
return 0, nil
}
i64, err := strconv.ParseInt(s, 10, 0)
// handle the case where the string might be a float
if err != nil && checkfn.IsNumeric(s) {
var floatVal float64
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
i64 = int64(math.Round(floatVal))
err = nil
}
}
return i64, err
}
// TryStrUint64 try to convert string to uint64, return error on failed
//
// - empty string will return 0.
// - allow float string.
func TryStrUint64(s string) (uint64, error) {
s = strings.TrimSpace(s)
if s == "" {
return 0, nil
}
// try convert to int64
u64, err := strconv.ParseUint(s, 10, 0)
// handle the case where the string might be a float
if err != nil && checkfn.IsPositiveNum(s) {
var floatVal float64
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
u64 = uint64(math.Round(floatVal))
err = nil
}
}
return u64, err
}