// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // 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, // You can obtain one at https://github.com/gogf/gf. // Package gconv implements powerful and convenient converting functionality for any types of variables. // // This package should keep much less dependencies with other packages. package gconv import ( "context" "fmt" "math" "reflect" "strconv" "strings" "time" "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/internal/intlog" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gtag" ) var ( // Empty strings. emptyStringMap = map[string]struct{}{ "": {}, "0": {}, "no": {}, "off": {}, "false": {}, } // StructTagPriority defines the default priority tags for Map*/Struct* functions. // Note that, the `gconv/param` tags are used by old version of package. // It is strongly recommended using short tag `c/p` instead in the future. StructTagPriority = []string{ gtag.GConv, gtag.Param, gtag.GConvShort, gtag.ParamShort, gtag.Json, } ) // Byte converts `any` to byte. func Byte(any interface{}) byte { if v, ok := any.(byte); ok { return v } return Uint8(any) } // Bytes converts `any` to []byte. func Bytes(any interface{}) []byte { if any == nil { return nil } switch value := any.(type) { case string: return []byte(value) case []byte: return value default: if f, ok := value.(iBytes); ok { return f.Bytes() } originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { case reflect.Map: bytes, err := json.Marshal(any) if err != nil { intlog.Errorf(context.TODO(), `%+v`, err) } return bytes case reflect.Array, reflect.Slice: var ( ok = true bytes = make([]byte, originValueAndKind.OriginValue.Len()) ) for i := range bytes { int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface()) if int32Value < 0 || int32Value > math.MaxUint8 { ok = false break } bytes[i] = byte(int32Value) } if ok { return bytes } } return gbinary.Encode(any) } } // Rune converts `any` to rune. func Rune(any interface{}) rune { if v, ok := any.(rune); ok { return v } return Int32(any) } // Runes converts `any` to []rune. func Runes(any interface{}) []rune { if v, ok := any.([]rune); ok { return v } return []rune(String(any)) } // String converts `any` to string. // It's most commonly used converting function. func String(any interface{}) string { if any == nil { return "" } switch value := any.(type) { case int: return strconv.Itoa(value) case int8: return strconv.Itoa(int(value)) case int16: return strconv.Itoa(int(value)) case int32: return strconv.Itoa(int(value)) case int64: return strconv.FormatInt(value, 10) 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: return strconv.FormatUint(value, 10) 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) case time.Time: if value.IsZero() { return "" } return value.String() case *time.Time: if value == nil { return "" } return value.String() case gtime.Time: if value.IsZero() { return "" } return value.String() case *gtime.Time: if value == nil { return "" } return value.String() default: // Empty checks. if value == nil { return "" } if f, ok := value.(iString); ok { // If the variable implements the String() interface, // then use that interface to perform the conversion return f.String() } if f, ok := value.(iError); ok { // If the variable implements the Error() interface, // then use that interface to perform the conversion return f.Error() } // Reflect checks. var ( rv = reflect.ValueOf(value) kind = rv.Kind() ) switch kind { case reflect.Chan, reflect.Map, reflect.Slice, reflect.Func, reflect.Ptr, reflect.Interface, reflect.UnsafePointer: if rv.IsNil() { return "" } case reflect.String: return rv.String() } if kind == reflect.Ptr { return String(rv.Elem().Interface()) } // Finally, we use json.Marshal to convert. if jsonContent, err := json.Marshal(value); err != nil { return fmt.Sprint(value) } else { return string(jsonContent) } } } // Bool converts `any` to bool. // It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map. func Bool(any interface{}) bool { if any == nil { return false } switch value := any.(type) { case bool: return value case []byte: if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok { return false } return true case string: if _, ok := emptyStringMap[strings.ToLower(value)]; ok { return false } return true default: if f, ok := value.(iBool); ok { return f.Bool() } rv := reflect.ValueOf(any) switch rv.Kind() { case reflect.Ptr: return !rv.IsNil() case reflect.Map: fallthrough case reflect.Array: fallthrough case reflect.Slice: return rv.Len() != 0 case reflect.Struct: return true default: s := strings.ToLower(String(any)) if _, ok := emptyStringMap[s]; ok { return false } return true } } } // 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) { if err := json.UnmarshalUseNumber(r, &target); err != nil { return false } return true } case string: anyAsBytes := []byte(r) if json.Valid(anyAsBytes) { if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil { return false } return true } } return false }