2021-01-17 21:46:25 +08:00
|
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2017-12-31 11:09:16 +08:00
|
|
|
|
//
|
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2017-12-31 18:19:58 +08:00
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
|
// Package gconv implements powerful and convenient converting functionality for any types of variables.
|
2020-06-04 20:13:33 +08:00
|
|
|
|
//
|
2024-09-09 16:17:01 +08:00
|
|
|
|
// This package should keep much fewer dependencies with other packages.
|
2017-12-31 11:09:16 +08:00
|
|
|
|
package gconv
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2022-02-17 11:46:35 +08:00
|
|
|
|
"context"
|
2019-07-22 15:31:35 +08:00
|
|
|
|
"fmt"
|
2021-05-25 09:56:23 +08:00
|
|
|
|
"math"
|
2019-06-19 09:06:52 +08:00
|
|
|
|
"reflect"
|
|
|
|
|
|
"strconv"
|
2019-09-02 15:48:25 +08:00
|
|
|
|
"strings"
|
2019-11-21 21:49:00 +08:00
|
|
|
|
"time"
|
2019-07-04 11:11:41 +08:00
|
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
|
"github.com/gogf/gf/v2/encoding/gbinary"
|
2022-02-17 11:46:35 +08:00
|
|
|
|
"github.com/gogf/gf/v2/internal/intlog"
|
2021-11-13 23:30:31 +08:00
|
|
|
|
"github.com/gogf/gf/v2/internal/json"
|
2022-03-11 10:24:42 +08:00
|
|
|
|
"github.com/gogf/gf/v2/internal/reflection"
|
2021-11-13 23:30:31 +08:00
|
|
|
|
"github.com/gogf/gf/v2/os/gtime"
|
2024-09-09 16:17:01 +08:00
|
|
|
|
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
|
|
|
|
|
|
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
|
2017-12-31 11:09:16 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2019-03-15 00:22:39 +08:00
|
|
|
|
var (
|
2019-06-19 09:06:52 +08:00
|
|
|
|
// Empty strings.
|
|
|
|
|
|
emptyStringMap = map[string]struct{}{
|
2019-08-09 20:05:36 +08:00
|
|
|
|
"": {},
|
|
|
|
|
|
"0": {},
|
2019-09-02 15:48:25 +08:00
|
|
|
|
"no": {},
|
2019-08-09 20:05:36 +08:00
|
|
|
|
"off": {},
|
|
|
|
|
|
"false": {},
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
2019-03-15 00:22:39 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2024-09-23 11:50:48 +08:00
|
|
|
|
// IUnmarshalValue is the interface for custom defined types customizing value assignment.
|
|
|
|
|
|
// Note that only pointer can implement interface IUnmarshalValue.
|
|
|
|
|
|
type IUnmarshalValue = localinterface.IUnmarshalValue
|
|
|
|
|
|
|
2024-09-09 16:17:01 +08:00
|
|
|
|
func init() {
|
|
|
|
|
|
// register common converters for internal usage.
|
|
|
|
|
|
structcache.RegisterCommonConverter(structcache.CommonConverter{
|
|
|
|
|
|
Int64: Int64,
|
|
|
|
|
|
Uint64: Uint64,
|
|
|
|
|
|
String: String,
|
|
|
|
|
|
Float32: Float32,
|
|
|
|
|
|
Float64: Float64,
|
|
|
|
|
|
Time: Time,
|
|
|
|
|
|
GTime: GTime,
|
|
|
|
|
|
Bytes: Bytes,
|
|
|
|
|
|
Bool: Bool,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// Byte converts `any` to byte.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func Byte(any interface{}) byte {
|
|
|
|
|
|
if v, ok := any.(byte); ok {
|
2019-05-09 22:53:42 +08:00
|
|
|
|
return v
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
return Uint8(any)
|
2019-05-09 22:53:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// Bytes converts `any` to []byte.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func Bytes(any interface{}) []byte {
|
|
|
|
|
|
if any == nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
switch value := any.(type) {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case string:
|
|
|
|
|
|
return []byte(value)
|
2021-12-20 00:32:23 +08:00
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case []byte:
|
|
|
|
|
|
return value
|
2021-12-20 00:32:23 +08:00
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
|
default:
|
2024-09-09 16:17:01 +08:00
|
|
|
|
if f, ok := value.(localinterface.IBytes); ok {
|
2021-03-18 15:21:05 +08:00
|
|
|
|
return f.Bytes()
|
|
|
|
|
|
}
|
2022-03-11 10:24:42 +08:00
|
|
|
|
originValueAndKind := reflection.OriginValueAndKind(any)
|
2021-11-19 15:21:46 +08:00
|
|
|
|
switch originValueAndKind.OriginKind {
|
2022-02-17 11:46:35 +08:00
|
|
|
|
case reflect.Map:
|
|
|
|
|
|
bytes, err := json.Marshal(any)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
intlog.Errorf(context.TODO(), `%+v`, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return bytes
|
|
|
|
|
|
|
2021-05-25 09:56:23 +08:00
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
|
|
|
|
var (
|
|
|
|
|
|
ok = true
|
2021-11-19 15:21:46 +08:00
|
|
|
|
bytes = make([]byte, originValueAndKind.OriginValue.Len())
|
2021-05-25 09:56:23 +08:00
|
|
|
|
)
|
2022-11-01 20:12:21 +08:00
|
|
|
|
for i := range bytes {
|
2021-11-19 15:21:46 +08:00
|
|
|
|
int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface())
|
2021-05-25 09:56:23 +08:00
|
|
|
|
if int32Value < 0 || int32Value > math.MaxUint8 {
|
|
|
|
|
|
ok = false
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
bytes[i] = byte(int32Value)
|
|
|
|
|
|
}
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
return bytes
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
return gbinary.Encode(any)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
2018-01-03 10:23:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// Rune converts `any` to rune.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func Rune(any interface{}) rune {
|
|
|
|
|
|
if v, ok := any.(rune); ok {
|
2019-05-09 22:53:42 +08:00
|
|
|
|
return v
|
|
|
|
|
|
}
|
2021-05-25 09:56:23 +08:00
|
|
|
|
return Int32(any)
|
2019-05-09 22:53:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// Runes converts `any` to []rune.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func Runes(any interface{}) []rune {
|
|
|
|
|
|
if v, ok := any.([]rune); ok {
|
2019-05-09 22:53:42 +08:00
|
|
|
|
return v
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
return []rune(String(any))
|
2019-05-09 22:53:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// String converts `any` to string.
|
2022-10-18 19:13:14 +08:00
|
|
|
|
// It's most commonly used converting function.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func String(any interface{}) string {
|
|
|
|
|
|
if any == nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return ""
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
switch value := any.(type) {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case int:
|
2019-09-29 15:59:09 +08:00
|
|
|
|
return strconv.Itoa(value)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case int8:
|
|
|
|
|
|
return strconv.Itoa(int(value))
|
|
|
|
|
|
case int16:
|
|
|
|
|
|
return strconv.Itoa(int(value))
|
|
|
|
|
|
case int32:
|
|
|
|
|
|
return strconv.Itoa(int(value))
|
|
|
|
|
|
case int64:
|
2019-09-29 15:59:09 +08:00
|
|
|
|
return strconv.FormatInt(value, 10)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case uint:
|
|
|
|
|
|
return strconv.FormatUint(uint64(value), 10)
|
|
|
|
|
|
case uint8:
|
|
|
|
|
|
return strconv.FormatUint(uint64(value), 10)
|
|
|
|
|
|
case uint16:
|
|
|
|
|
|
return strconv.FormatUint(uint64(value), 10)
|
|
|
|
|
|
case uint32:
|
|
|
|
|
|
return strconv.FormatUint(uint64(value), 10)
|
|
|
|
|
|
case uint64:
|
2019-09-29 15:59:09 +08:00
|
|
|
|
return strconv.FormatUint(value, 10)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case float32:
|
|
|
|
|
|
return strconv.FormatFloat(float64(value), 'f', -1, 32)
|
|
|
|
|
|
case float64:
|
|
|
|
|
|
return strconv.FormatFloat(value, 'f', -1, 64)
|
|
|
|
|
|
case bool:
|
|
|
|
|
|
return strconv.FormatBool(value)
|
|
|
|
|
|
case string:
|
|
|
|
|
|
return value
|
|
|
|
|
|
case []byte:
|
|
|
|
|
|
return string(value)
|
2020-02-16 22:39:12 +08:00
|
|
|
|
case time.Time:
|
|
|
|
|
|
if value.IsZero() {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return value.String()
|
2019-11-21 21:49:00 +08:00
|
|
|
|
case *time.Time:
|
|
|
|
|
|
if value == nil {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return value.String()
|
2020-02-16 22:39:12 +08:00
|
|
|
|
case gtime.Time:
|
|
|
|
|
|
if value.IsZero() {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return value.String()
|
2019-11-21 21:49:00 +08:00
|
|
|
|
case *gtime.Time:
|
|
|
|
|
|
if value == nil {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return value.String()
|
2019-06-19 09:06:52 +08:00
|
|
|
|
default:
|
2024-09-09 16:17:01 +08:00
|
|
|
|
if f, ok := value.(localinterface.IString); ok {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
// If the variable implements the String() interface,
|
|
|
|
|
|
// then use that interface to perform the conversion
|
|
|
|
|
|
return f.String()
|
2020-04-07 21:29:41 +08:00
|
|
|
|
}
|
2024-09-09 16:17:01 +08:00
|
|
|
|
if f, ok := value.(localinterface.IError); ok {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
// If the variable implements the Error() interface,
|
|
|
|
|
|
// then use that interface to perform the conversion
|
|
|
|
|
|
return f.Error()
|
2020-04-07 21:29:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
// Reflect checks.
|
2020-09-18 23:59:49 +08:00
|
|
|
|
var (
|
|
|
|
|
|
rv = reflect.ValueOf(value)
|
|
|
|
|
|
kind = rv.Kind()
|
|
|
|
|
|
)
|
2020-04-07 21:29:41 +08:00
|
|
|
|
switch kind {
|
2024-09-12 21:59:38 +08:00
|
|
|
|
case
|
|
|
|
|
|
reflect.Chan,
|
2020-04-07 21:29:41 +08:00
|
|
|
|
reflect.Map,
|
|
|
|
|
|
reflect.Slice,
|
|
|
|
|
|
reflect.Func,
|
|
|
|
|
|
reflect.Interface,
|
|
|
|
|
|
reflect.UnsafePointer:
|
|
|
|
|
|
if rv.IsNil() {
|
|
|
|
|
|
return ""
|
2019-07-22 15:31:35 +08:00
|
|
|
|
}
|
2020-09-18 23:59:49 +08:00
|
|
|
|
case reflect.String:
|
|
|
|
|
|
return rv.String()
|
2024-09-12 21:59:38 +08:00
|
|
|
|
case reflect.Ptr:
|
|
|
|
|
|
if rv.IsNil() {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
2020-04-07 21:29:41 +08:00
|
|
|
|
return String(rv.Elem().Interface())
|
2024-09-12 21:59:38 +08:00
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
|
|
return strconv.FormatInt(rv.Int(), 10)
|
|
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
|
|
return strconv.FormatUint(rv.Uint(), 10)
|
|
|
|
|
|
case reflect.Uintptr:
|
|
|
|
|
|
return strconv.FormatUint(rv.Uint(), 10)
|
|
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
|
|
return strconv.FormatFloat(rv.Float(), 'f', -1, 64)
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
|
return strconv.FormatBool(rv.Bool())
|
2020-04-07 21:29:41 +08:00
|
|
|
|
}
|
2021-08-04 20:50:45 +08:00
|
|
|
|
// Finally, we use json.Marshal to convert.
|
2020-04-07 21:29:41 +08:00
|
|
|
|
if jsonContent, err := json.Marshal(value); err != nil {
|
|
|
|
|
|
return fmt.Sprint(value)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return string(jsonContent)
|
|
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
2017-12-31 11:09:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-17 21:26:39 +08:00
|
|
|
|
// Bool converts `any` to bool.
|
|
|
|
|
|
// It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
|
2021-02-05 14:44:20 +08:00
|
|
|
|
func Bool(any interface{}) bool {
|
|
|
|
|
|
if any == nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return false
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
switch value := any.(type) {
|
2019-07-20 16:41:17 +08:00
|
|
|
|
case bool:
|
|
|
|
|
|
return value
|
2019-08-22 23:24:45 +08:00
|
|
|
|
case []byte:
|
2019-09-02 15:48:25 +08:00
|
|
|
|
if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
|
2019-08-22 23:24:45 +08:00
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
2019-07-20 16:41:17 +08:00
|
|
|
|
case string:
|
2019-09-02 15:48:25 +08:00
|
|
|
|
if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
default:
|
2024-09-09 16:17:01 +08:00
|
|
|
|
if f, ok := value.(localinterface.IBool); ok {
|
2021-03-18 15:21:05 +08:00
|
|
|
|
return f.Bool()
|
|
|
|
|
|
}
|
2021-02-05 14:44:20 +08:00
|
|
|
|
rv := reflect.ValueOf(any)
|
2019-07-20 16:41:17 +08:00
|
|
|
|
switch rv.Kind() {
|
|
|
|
|
|
case reflect.Ptr:
|
2024-09-12 21:59:38 +08:00
|
|
|
|
if rv.IsNil() {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if rv.Type().Elem().Kind() == reflect.Bool {
|
|
|
|
|
|
return rv.Elem().Bool()
|
|
|
|
|
|
}
|
|
|
|
|
|
return Bool(rv.Elem().Interface())
|
|
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
|
|
return rv.Int() != 0
|
|
|
|
|
|
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
|
|
return rv.Uint() != 0
|
|
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
|
|
return rv.Float() != 0
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
|
return rv.Bool()
|
|
|
|
|
|
// TODO:(Map,Array,Slice,Struct) It might panic here for these types.
|
|
|
|
|
|
case reflect.Map, reflect.Array:
|
2019-07-20 16:41:17 +08:00
|
|
|
|
fallthrough
|
|
|
|
|
|
case reflect.Slice:
|
|
|
|
|
|
return rv.Len() != 0
|
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
|
return true
|
|
|
|
|
|
default:
|
2021-02-05 14:44:20 +08:00
|
|
|
|
s := strings.ToLower(String(any))
|
2019-07-20 16:41:17 +08:00
|
|
|
|
if _, ok := emptyStringMap[s]; ok {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-31 11:09:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-15 21:17:45 +08:00
|
|
|
|
// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`.
|
|
|
|
|
|
func checkJsonAndUnmarshalUseNumber(any interface{}, target interface{}) bool {
|
|
|
|
|
|
switch r := any.(type) {
|
|
|
|
|
|
case []byte:
|
|
|
|
|
|
if json.Valid(r) {
|
2022-04-18 20:57:41 +08:00
|
|
|
|
if err := json.UnmarshalUseNumber(r, &target); err != nil {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
2021-09-15 21:17:45 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case string:
|
|
|
|
|
|
anyAsBytes := []byte(r)
|
|
|
|
|
|
if json.Valid(anyAsBytes) {
|
2022-04-18 20:57:41 +08:00
|
|
|
|
if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
2021-09-15 21:17:45 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|