From bd5b6a1ed747c9d3d69a87d1fc4f5806ffb8814c Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:16:48 +0800 Subject: [PATCH] up --- util/gconv/gconv.go | 2 +- util/gconv/gconv_convert.go | 18 +- util/gconv/gconv_converter.go | 529 ++-------- util/gconv/gconv_converter_bool.go | 3 +- util/gconv/gconv_converter_builtin.go | 16 +- util/gconv/gconv_converter_bytes.go | 2 +- util/gconv/gconv_converter_convert.go | 522 ++++++++++ util/gconv/gconv_converter_doMapConvert.go | 504 +++++++++ util/gconv/gconv_converter_float.go | 4 +- util/gconv/gconv_converter_int.go | 10 +- util/gconv/gconv_converter_map.go | 983 +++++++++--------- util/gconv/gconv_converter_maps.go | 7 - util/gconv/gconv_converter_maptomap.go | 42 +- util/gconv/gconv_converter_maptomaps.go | 2 +- util/gconv/gconv_converter_rune.go | 4 +- util/gconv/gconv_converter_scan.go | 4 +- util/gconv/gconv_converter_slice_any.go | 142 +++ util/gconv/gconv_converter_slice_float.go | 417 ++++++++ util/gconv/gconv_converter_slice_int.go | 536 ++++++++++ util/gconv/gconv_converter_slice_map.go | 59 ++ util/gconv/gconv_converter_slice_str.go | 216 ++++ util/gconv/gconv_converter_slice_uint.go | 527 ++++++++++ util/gconv/gconv_converter_string.go | 2 +- util/gconv/gconv_converter_struct.go | 12 +- util/gconv/gconv_converter_structs.go | 2 +- util/gconv/gconv_converter_time.go | 6 +- util/gconv/gconv_converter_uint.go | 10 +- util/gconv/gconv_slice_any.go | 132 +-- util/gconv/gconv_slice_float.go | 278 +---- util/gconv/gconv_slice_int.go | 453 +------- util/gconv/gconv_slice_str.go | 149 +-- util/gconv/gconv_slice_uint.go | 432 +------- .../gconv/internal/structcache/structcache.go | 19 +- .../structcache/structcache_cached.go | 8 +- 34 files changed, 3598 insertions(+), 2454 deletions(-) create mode 100644 util/gconv/gconv_converter_convert.go create mode 100644 util/gconv/gconv_converter_doMapConvert.go delete mode 100644 util/gconv/gconv_converter_maps.go create mode 100644 util/gconv/gconv_converter_slice_any.go create mode 100644 util/gconv/gconv_converter_slice_float.go create mode 100644 util/gconv/gconv_converter_slice_int.go create mode 100644 util/gconv/gconv_converter_slice_map.go create mode 100644 util/gconv/gconv_converter_slice_str.go create mode 100644 util/gconv/gconv_converter_slice_uint.go diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 00748eb06..be49d479a 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -39,7 +39,7 @@ var ( // RegisterConverter registers custom converter. // Deprecated: use RegisterTypeConverterFunc instead for clear func RegisterConverter(fn any) (err error) { - return defaultConverter.RegisterTypeConverterFunc(fn) + return RegisterTypeConverterFunc(fn) } // RegisterTypeConverterFunc registers custom converter. diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 6603469a2..53db02f1c 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -15,7 +15,7 @@ import ( // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func Convert(fromValue any, toTypeName string, extraParams ...any) any { - return defaultConverter.doConvert( + result, _ := defaultConverter.doConvert( doConvertInput{ FromValue: fromValue, ToTypeName: toTypeName, @@ -23,6 +23,7 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any { Extra: extraParams, }, ) + return result } // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`. @@ -36,12 +37,11 @@ func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any { } else { referValueRf = reflect.ValueOf(referValue) } - return defaultConverter.doConvert( - doConvertInput{ - FromValue: fromValue, - ToTypeName: referValueRf.Type().String(), - ReferValue: referValue, - Extra: extraParams, - }, - ) + result, _ := defaultConverter.doConvert(doConvertInput{ + FromValue: fromValue, + ToTypeName: referValueRf.Type().String(), + ReferValue: referValue, + Extra: extraParams, + }) + return result } diff --git a/util/gconv/gconv_converter.go b/util/gconv/gconv_converter.go index 2a4803cd3..68fe71a14 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/gconv_converter.go @@ -7,14 +7,11 @@ package gconv import ( - "context" "reflect" "time" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) @@ -26,9 +23,49 @@ type ( ) // Converter is the manager for type converting. -type Converter struct { - internalConvertConfig *structcache.ConvertConfig - typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc +type Converter interface { + RegisterTypeConverterFunc(fn any) (err error) + ConverterForInt + ConverterForUint + String(any any) (string, error) + Bool(any any) (bool, error) + Bytes(any any) ([]byte, error) + Float32(any any) (float32, error) + Float64(any any) (float64, error) + + doMapConvert( + value any, recursive recursiveType, mustMapReturn bool, option ...MapOption, + ) map[string]any + MapToMap(params any, pointer any, mapping ...map[string]string) (err error) + MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) + Rune(any any) (rune, error) + Runes(any any) ([]rune, error) + Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) + Time(any interface{}, format ...string) (time.Time, error) + Duration(any interface{}) (time.Duration, error) + GTime(any interface{}, format ...string) (*gtime.Time, error) +} + +type ConverterForInt interface { + Int(any any) (int, error) + Int8(any any) (int8, error) + Int16(any any) (int16, error) + Int32(any any) (int32, error) + Int64(any any) (int64, error) +} + +type ConverterForUint interface { + Uint(any any) (uint, error) + Uint8(any any) (uint8, error) + Uin16(any any) (uint16, error) + Uint32(any any) (uint32, error) + Uint64(any any) (uint64, error) +} + +// impConverter implements the interface Converter. +type impConverter struct { + internalConverter *structcache.Converter + typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc } var ( @@ -57,48 +94,15 @@ var ( ) // NewConverter creates and returns management object for type converting. -func NewConverter() *Converter { - cf := &Converter{ - internalConvertConfig: structcache.NewConvertConfig(), - typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), +func NewConverter() *impConverter { + cf := &impConverter{ + internalConverter: structcache.NewConverter(), + typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), } cf.registerBuiltInConverter() return cf } -func (c *Converter) registerBuiltInConverter() { - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForString, stringType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForBool, boolType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForBytes, bytesType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForTime, timeType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForGTime, gtimeType, - ) -} - -func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { - for _, t := range types { - c.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc) - } -} - // RegisterTypeConverterFunc registers custom converter. // It must be registered before you use this custom converting feature. // It is suggested to do it in boot procedure of the process. @@ -107,7 +111,7 @@ func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, t // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { +func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) { var ( fnReflectType = reflect.TypeOf(fn) errType = reflect.TypeOf((*error)(nil)).Elem() @@ -160,418 +164,39 @@ func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { return } registeredOutTypeMap[outType] = reflect.ValueOf(fn) - c.internalConvertConfig.RegisterTypeConvertFunc(outType) + c.internalConverter.RegisterTypeConvertFunc(outType) return } -func (c *Converter) getRegisteredConverterFuncAndSrcType( - srcReflectValue, dstReflectValueForRefer reflect.Value, -) (f converterFunc, srcType reflect.Type, ok bool) { - if len(c.typeConverterFuncMap) == 0 { - return reflect.Value{}, nil, false - } - srcType = srcReflectValue.Type() - for srcType.Kind() == reflect.Pointer { - srcType = srcType.Elem() - } - var registeredOutTypeMap map[converterOutType]converterFunc - // firstly, it searches the map by input parameter type. - registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType] - if !ok { - return reflect.Value{}, nil, false - } - var dstType = dstReflectValueForRefer.Type() - if dstType.Kind() == reflect.Pointer { - // Might be **struct, which is support as designed. - if dstType.Elem().Kind() == reflect.Pointer { - dstType = dstType.Elem() - } - } else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() { - dstType = dstReflectValueForRefer.Addr().Type() - } else { - dstType = reflect.PointerTo(dstType) - } - // secondly, it searches the input parameter type map - // and finds the result converter function by the output parameter type. - f, ok = registeredOutTypeMap[dstType] - if !ok { - return reflect.Value{}, nil, false - } - return +func (c *impConverter) registerBuiltInConverter() { + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForString, stringType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBool, boolType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBytes, bytesType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForTime, timeType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForGTime, gtimeType, + ) } -func (c *Converter) callCustomConverterWithRefer( - srcReflectValue, referReflectValue reflect.Value, -) (dstReflectValue reflect.Value, converted bool, err error) { - registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) - if !ok { - return reflect.Value{}, false, nil - } - dstReflectValue = reflect.New(referReflectValue.Type()).Elem() - converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) - return -} - -// callCustomConverter call the custom converter. It will try some possible type. -func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { - registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) - if !ok { - return false, nil - } - return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) -} - -func (c *Converter) doCallCustomConverter( - srcReflectValue reflect.Value, - dstReflectValue reflect.Value, - registeredConverterFunc converterFunc, - srcType reflect.Type, -) (converted bool, err error) { - // Converter function calling. - for srcReflectValue.Type() != srcType { - srcReflectValue = srcReflectValue.Elem() - } - result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue}) - if !result[1].IsNil() { - return false, result[1].Interface().(error) - } - // The `result[0]` is a pointer. - if result[0].IsNil() { - return false, nil - } - var resultValue = result[0] - for { - if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() { - dstReflectValue.Set(resultValue) - converted = true - } else if dstReflectValue.Kind() == reflect.Pointer { - if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() { - dstReflectValue.Elem().Set(resultValue) - converted = true - } - } - if converted { - break - } - if resultValue.Kind() == reflect.Pointer { - resultValue = resultValue.Elem() - } else { - break - } - } - - return converted, nil -} - -type doConvertInput struct { - FromValue interface{} // Value that is converted from. - ToTypeName string // Target value type name in string. - ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. - Extra []interface{} // Extra values for implementing the converting. - - // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. - // It is an attribute for internal usage purpose. - alreadySetToReferValue bool -} - -// doConvert does commonly use types converting. -func (c *Converter) doConvert(in doConvertInput) (convertedValue interface{}) { - switch in.ToTypeName { - case "int": - return Int(in.FromValue) - case "*int": - if _, ok := in.FromValue.(*int); ok { - return in.FromValue - } - v := Int(in.FromValue) - return &v - - case "int8": - return Int8(in.FromValue) - case "*int8": - if _, ok := in.FromValue.(*int8); ok { - return in.FromValue - } - v := Int8(in.FromValue) - return &v - - case "int16": - return Int16(in.FromValue) - case "*int16": - if _, ok := in.FromValue.(*int16); ok { - return in.FromValue - } - v := Int16(in.FromValue) - return &v - - case "int32": - return Int32(in.FromValue) - case "*int32": - if _, ok := in.FromValue.(*int32); ok { - return in.FromValue - } - v := Int32(in.FromValue) - return &v - - case "int64": - return Int64(in.FromValue) - case "*int64": - if _, ok := in.FromValue.(*int64); ok { - return in.FromValue - } - v := Int64(in.FromValue) - return &v - - case "uint": - return Uint(in.FromValue) - case "*uint": - if _, ok := in.FromValue.(*uint); ok { - return in.FromValue - } - v := Uint(in.FromValue) - return &v - - case "uint8": - return Uint8(in.FromValue) - case "*uint8": - if _, ok := in.FromValue.(*uint8); ok { - return in.FromValue - } - v := Uint8(in.FromValue) - return &v - - case "uint16": - return Uint16(in.FromValue) - case "*uint16": - if _, ok := in.FromValue.(*uint16); ok { - return in.FromValue - } - v := Uint16(in.FromValue) - return &v - - case "uint32": - return Uint32(in.FromValue) - case "*uint32": - if _, ok := in.FromValue.(*uint32); ok { - return in.FromValue - } - v := Uint32(in.FromValue) - return &v - - case "uint64": - return Uint64(in.FromValue) - case "*uint64": - if _, ok := in.FromValue.(*uint64); ok { - return in.FromValue - } - v := Uint64(in.FromValue) - return &v - - case "float32": - return Float32(in.FromValue) - case "*float32": - if _, ok := in.FromValue.(*float32); ok { - return in.FromValue - } - v := Float32(in.FromValue) - return &v - - case "float64": - return Float64(in.FromValue) - case "*float64": - if _, ok := in.FromValue.(*float64); ok { - return in.FromValue - } - v := Float64(in.FromValue) - return &v - - case "bool": - return Bool(in.FromValue) - case "*bool": - if _, ok := in.FromValue.(*bool); ok { - return in.FromValue - } - v := Bool(in.FromValue) - return &v - - case "string": - return String(in.FromValue) - case "*string": - if _, ok := in.FromValue.(*string); ok { - return in.FromValue - } - v := String(in.FromValue) - return &v - - case "[]byte": - return Bytes(in.FromValue) - case "[]int": - return Ints(in.FromValue) - case "[]int32": - return Int32s(in.FromValue) - case "[]int64": - return Int64s(in.FromValue) - case "[]uint": - return Uints(in.FromValue) - case "[]uint8": - return Bytes(in.FromValue) - case "[]uint32": - return Uint32s(in.FromValue) - case "[]uint64": - return Uint64s(in.FromValue) - case "[]float32": - return Float32s(in.FromValue) - case "[]float64": - return Float64s(in.FromValue) - case "[]string": - return Strings(in.FromValue) - - case "Time", "time.Time": - if len(in.Extra) > 0 { - return Time(in.FromValue, String(in.Extra[0])) - } - return Time(in.FromValue) - case "*time.Time": - var v time.Time - if len(in.Extra) > 0 { - v = Time(in.FromValue, String(in.Extra[0])) - } else { - if _, ok := in.FromValue.(*time.Time); ok { - return in.FromValue - } - v = Time(in.FromValue) - } - return &v - - case "GTime", "gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return *v - } else { - return *gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return *v - } else { - return *gtime.New() - } - case "*gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return v - } else { - return gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return v - } else { - return gtime.New() - } - - case "Duration", "time.Duration": - return Duration(in.FromValue) - case "*time.Duration": - if _, ok := in.FromValue.(*time.Duration); ok { - return in.FromValue - } - v := Duration(in.FromValue) - return &v - - case "map[string]string": - return MapStrStr(in.FromValue) - - case "map[string]interface {}": - return Map(in.FromValue) - - case "[]map[string]interface {}": - return Maps(in.FromValue) - - case "RawMessage", "json.RawMessage": - // issue 3449 - bytes, err := json.Marshal(in.FromValue) - if err != nil { - intlog.Errorf(context.TODO(), `%+v`, err) - } - return bytes - - default: - if in.ReferValue != nil { - var referReflectValue reflect.Value - if v, ok := in.ReferValue.(reflect.Value); ok { - referReflectValue = v - } else { - referReflectValue = reflect.ValueOf(in.ReferValue) - } - var fromReflectValue reflect.Value - if v, ok := in.FromValue.(reflect.Value); ok { - fromReflectValue = v - } else { - fromReflectValue = reflect.ValueOf(in.FromValue) - } - - // custom converter. - if dstReflectValue, ok, _ := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { - return dstReflectValue.Interface() - } - - defer func() { - if recover() != nil { - in.alreadySetToReferValue = false - if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { - in.alreadySetToReferValue = true - convertedValue = referReflectValue.Interface() - } - } - }() - switch referReflectValue.Kind() { - case reflect.Ptr: - // Type converting for custom type pointers. - // Eg: - // type PayMode int - // type Req struct{ - // Mode *PayMode - // } - // - // Struct(`{"Mode": 1000}`, &req) - originType := referReflectValue.Type().Elem() - switch originType.Kind() { - case reflect.Struct: - // Not support some kinds. - default: - in.ToTypeName = originType.Kind().String() - in.ReferValue = nil - refElementValue := reflect.ValueOf(c.doConvert(in)) - originTypeValue := reflect.New(refElementValue.Type()).Elem() - originTypeValue.Set(refElementValue) - in.alreadySetToReferValue = true - return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface() - } - - case reflect.Map: - var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err := c.MapToMap(in.FromValue, targetValue); err == nil { - in.alreadySetToReferValue = true - } - return targetValue.Interface() - - default: - - } - in.ToTypeName = referReflectValue.Kind().String() - in.ReferValue = nil - in.alreadySetToReferValue = true - convertedValue = reflect.ValueOf(c.doConvert(in)).Convert(referReflectValue.Type()).Interface() - return convertedValue - } - return in.FromValue - } -} - -func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) { - convertedValue := c.doConvert(in) - if !in.alreadySetToReferValue { - reflectValue.Set(reflect.ValueOf(convertedValue)) +func (c *impConverter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { + for _, t := range types { + c.internalConverter.RegisterAnyConvertFunc(t, convertFunc) } } diff --git a/util/gconv/gconv_converter_bool.go b/util/gconv/gconv_converter_bool.go index 94e26bea2..5b080d9df 100644 --- a/util/gconv/gconv_converter_bool.go +++ b/util/gconv/gconv_converter_bool.go @@ -14,7 +14,8 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Bool(any any) (bool, error) { +// Bool converts `any` to bool. +func (c *impConverter) Bool(any any) (bool, error) { if empty.IsNil(any) { return false, nil } diff --git a/util/gconv/gconv_converter_builtin.go b/util/gconv/gconv_converter_builtin.go index 5009e6d46..2d8a3aee1 100644 --- a/util/gconv/gconv_converter_builtin.go +++ b/util/gconv/gconv_converter_builtin.go @@ -13,7 +13,7 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) -func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { v, err := c.Int64(from) if err != nil { return err @@ -22,7 +22,7 @@ func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) er return nil } -func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { v, err := c.Uint64(from) if err != nil { return err @@ -31,7 +31,7 @@ func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) e return nil } -func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { v, err := c.String(from) if err != nil { return err @@ -40,7 +40,7 @@ func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) e return nil } -func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { v, err := c.Float64(from) if err != nil { return err @@ -49,7 +49,7 @@ func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) return nil } -func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { v, err := c.Bool(from) if err != nil { return err @@ -58,7 +58,7 @@ func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) err return nil } -func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { v, err := c.Bytes(from) if err != nil { return err @@ -67,7 +67,7 @@ func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) er return nil } -func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { t, err := c.Time(from) if err != nil { return err @@ -76,7 +76,7 @@ func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) err return nil } -func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { v, err := c.GTime(from) if err != nil { return err diff --git a/util/gconv/gconv_converter_bytes.go b/util/gconv/gconv_converter_bytes.go index 3237bd4bb..437f90780 100644 --- a/util/gconv/gconv_converter_bytes.go +++ b/util/gconv/gconv_converter_bytes.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Bytes(any any) ([]byte, error) { +func (c *impConverter) Bytes(any any) ([]byte, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/gconv_converter_convert.go b/util/gconv/gconv_converter_convert.go new file mode 100644 index 000000000..74ca4660f --- /dev/null +++ b/util/gconv/gconv_converter_convert.go @@ -0,0 +1,522 @@ +// 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 + +import ( + "reflect" + "time" + + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" +) + +type doConvertInput struct { + FromValue any // Value that is converted from. + ToTypeName string // Target value type name in string. + ReferValue any // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. + Extra []any // Extra values for implementing the converting. + + // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. + // It is an attribute for internal usage purpose. + alreadySetToReferValue bool +} + +// doConvert does commonly use types converting. +func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err error) { + switch in.ToTypeName { + case "int": + return c.Int(in.FromValue) + case "*int": + if _, ok := in.FromValue.(*int); ok { + return in.FromValue, nil + } + v, err := c.Int(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int8": + return c.Int8(in.FromValue) + case "*int8": + if _, ok := in.FromValue.(*int8); ok { + return in.FromValue, nil + } + v, err := c.Int8(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int16": + return c.Int16(in.FromValue) + case "*int16": + if _, ok := in.FromValue.(*int16); ok { + return in.FromValue, nil + } + v, err := c.Int16(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int32": + return c.Int32(in.FromValue) + case "*int32": + if _, ok := in.FromValue.(*int32); ok { + return in.FromValue, nil + } + v, err := c.Int32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int64": + return c.Int64(in.FromValue) + case "*int64": + if _, ok := in.FromValue.(*int64); ok { + return in.FromValue, nil + } + v, err := c.Int64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint": + return c.Uint(in.FromValue) + case "*uint": + if _, ok := in.FromValue.(*uint); ok { + return in.FromValue, nil + } + v, err := c.Uint(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint8": + return c.Uint8(in.FromValue) + case "*uint8": + if _, ok := in.FromValue.(*uint8); ok { + return in.FromValue, nil + } + v, err := c.Uint8(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint16": + return c.Uint16(in.FromValue) + case "*uint16": + if _, ok := in.FromValue.(*uint16); ok { + return in.FromValue, nil + } + v, err := c.Uint16(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint32": + return c.Uint32(in.FromValue) + case "*uint32": + if _, ok := in.FromValue.(*uint32); ok { + return in.FromValue, nil + } + v, err := c.Uint32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint64": + return c.Uint64(in.FromValue) + case "*uint64": + if _, ok := in.FromValue.(*uint64); ok { + return in.FromValue, nil + } + v, err := c.Uint64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "float32": + return c.Float32(in.FromValue) + case "*float32": + if _, ok := in.FromValue.(*float32); ok { + return in.FromValue, nil + } + v, err := c.Float32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "float64": + return c.Float64(in.FromValue) + case "*float64": + if _, ok := in.FromValue.(*float64); ok { + return in.FromValue, nil + } + v, err := c.Float64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "bool": + return c.Bool(in.FromValue) + case "*bool": + if _, ok := in.FromValue.(*bool); ok { + return in.FromValue, nil + } + v, err := c.Bool(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "string": + return c.String(in.FromValue) + case "*string": + if _, ok := in.FromValue.(*string); ok { + return in.FromValue, nil + } + v, err := c.String(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "[]byte": + return c.Bytes(in.FromValue) + case "[]int": + return c.SliceInt(in.FromValue, SliceOption{}) + case "[]int32": + return c.SliceInt32(in.FromValue, SliceOption{}) + case "[]int64": + return c.SliceInt64(in.FromValue, SliceOption{}) + case "[]uint": + return c.SliceUint(in.FromValue, SliceOption{}) + case "[]uint8": + return c.Bytes(in.FromValue) + case "[]uint32": + return c.SliceUint32(in.FromValue, SliceOption{}) + case "[]uint64": + return c.SliceUint64(in.FromValue, SliceOption{}) + case "[]float32": + return c.SliceFloat32(in.FromValue, SliceOption{}) + case "[]float64": + return c.SliceFloat64(in.FromValue, SliceOption{}) + case "[]string": + return c.SliceStr(in.FromValue, SliceOption{}) + + case "Time", "time.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return nil, err + } + return c.Time(in.FromValue, s) + } + return c.Time(in.FromValue) + case "*time.Time": + var v time.Time + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return time.Time{}, err + } + v, err = c.Time(in.FromValue, s) + if err != nil { + return time.Time{}, err + } + } else { + if _, ok := in.FromValue.(*time.Time); ok { + return in.FromValue, nil + } + v, err = c.Time(in.FromValue) + if err != nil { + return time.Time{}, err + } + } + return &v, nil + + case "GTime", "gtime.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return *gtime.New(), err + } + v, err := c.GTime(in.FromValue, s) + if err != nil { + return *gtime.New(), err + } + if v != nil { + return *v, nil + } + return *gtime.New(), nil + } + v, err := c.GTime(in.FromValue) + if err != nil { + return *gtime.New(), err + } + if v != nil { + return *v, nil + } + return *gtime.New(), nil + case "*gtime.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return gtime.New(), err + } + v, err := c.GTime(in.FromValue, s) + if err != nil { + return gtime.New(), err + } + if v != nil { + return v, nil + } + return gtime.New(), nil + } + v, err := c.GTime(in.FromValue) + if err != nil { + return gtime.New(), err + } + if v != nil { + return v, nil + } + return gtime.New(), nil + + case "Duration", "time.Duration": + return c.Duration(in.FromValue) + case "*time.Duration": + if _, ok := in.FromValue.(*time.Duration); ok { + return in.FromValue, nil + } + v, err := c.Duration(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "map[string]string": + return MapStrStr(in.FromValue), nil + + case "map[string]interface {}": + return Map(in.FromValue, MapOption{}), nil + + case "[]map[string]interface {}": + return c.SliceMap(in.FromValue, SliceOption{}, MapOption{}) + + case "RawMessage", "json.RawMessage": + // issue 3449 + bytes, err := json.Marshal(in.FromValue) + if err != nil { + return nil, err + } + return bytes, nil + + default: + if in.ReferValue != nil { + var referReflectValue reflect.Value + if v, ok := in.ReferValue.(reflect.Value); ok { + referReflectValue = v + } else { + referReflectValue = reflect.ValueOf(in.ReferValue) + } + var fromReflectValue reflect.Value + if v, ok := in.FromValue.(reflect.Value); ok { + fromReflectValue = v + } else { + fromReflectValue = reflect.ValueOf(in.FromValue) + } + + // custom converter. + dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue) + if err != nil { + return nil, err + } + if ok { + return dstReflectValue.Interface(), nil + } + + defer func() { + if recover() != nil { + in.alreadySetToReferValue = false + if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { + in.alreadySetToReferValue = true + convertedValue = referReflectValue.Interface() + } + } + }() + switch referReflectValue.Kind() { + case reflect.Ptr: + // Type converting for custom type pointers. + // Eg: + // type PayMode int + // type Req struct{ + // Mode *PayMode + // } + // + // Struct(`{"Mode": 1000}`, &req) + originType := referReflectValue.Type().Elem() + switch originType.Kind() { + case reflect.Struct: + // Not support some kinds. + default: + in.ToTypeName = originType.Kind().String() + in.ReferValue = nil + result, err := c.doConvert(in) + if err != nil { + return nil, err + } + refElementValue := reflect.ValueOf(result) + originTypeValue := reflect.New(refElementValue.Type()).Elem() + originTypeValue.Set(refElementValue) + in.alreadySetToReferValue = true + return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil + } + + case reflect.Map: + var targetValue = reflect.New(referReflectValue.Type()).Elem() + if err = c.MapToMap(in.FromValue, targetValue); err == nil { + in.alreadySetToReferValue = true + } + return targetValue.Interface(), nil + + default: + + } + in.ToTypeName = referReflectValue.Kind().String() + in.ReferValue = nil + in.alreadySetToReferValue = true + result, err := c.doConvert(in) + if err != nil { + return nil, err + } + convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface() + return convertedValue, nil + } + return in.FromValue, nil + } +} + +func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error { + convertedValue, err := c.doConvert(in) + if err != nil { + return err + } + if !in.alreadySetToReferValue { + reflectValue.Set(reflect.ValueOf(convertedValue)) + } + return err +} + +func (c *impConverter) getRegisteredConverterFuncAndSrcType( + srcReflectValue, dstReflectValueForRefer reflect.Value, +) (f converterFunc, srcType reflect.Type, ok bool) { + if len(c.typeConverterFuncMap) == 0 { + return reflect.Value{}, nil, false + } + srcType = srcReflectValue.Type() + for srcType.Kind() == reflect.Pointer { + srcType = srcType.Elem() + } + var registeredOutTypeMap map[converterOutType]converterFunc + // firstly, it searches the map by input parameter type. + registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType] + if !ok { + return reflect.Value{}, nil, false + } + var dstType = dstReflectValueForRefer.Type() + if dstType.Kind() == reflect.Pointer { + // Might be **struct, which is support as designed. + if dstType.Elem().Kind() == reflect.Pointer { + dstType = dstType.Elem() + } + } else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() { + dstType = dstReflectValueForRefer.Addr().Type() + } else { + dstType = reflect.PointerTo(dstType) + } + // secondly, it searches the input parameter type map + // and finds the result converter function by the output parameter type. + f, ok = registeredOutTypeMap[dstType] + if !ok { + return reflect.Value{}, nil, false + } + return +} + +func (c *impConverter) callCustomConverterWithRefer( + srcReflectValue, referReflectValue reflect.Value, +) (dstReflectValue reflect.Value, converted bool, err error) { + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) + if !ok { + return reflect.Value{}, false, nil + } + dstReflectValue = reflect.New(referReflectValue.Type()).Elem() + converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + return +} + +// callCustomConverter call the custom converter. It will try some possible type. +func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) + if !ok { + return false, nil + } + return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) +} + +func (c *impConverter) doCallCustomConverter( + srcReflectValue reflect.Value, + dstReflectValue reflect.Value, + registeredConverterFunc converterFunc, + srcType reflect.Type, +) (converted bool, err error) { + // Converter function calling. + for srcReflectValue.Type() != srcType { + srcReflectValue = srcReflectValue.Elem() + } + result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue}) + if !result[1].IsNil() { + return false, result[1].Interface().(error) + } + // The `result[0]` is a pointer. + if result[0].IsNil() { + return false, nil + } + var resultValue = result[0] + for { + if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() { + dstReflectValue.Set(resultValue) + converted = true + } else if dstReflectValue.Kind() == reflect.Pointer { + if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() { + dstReflectValue.Elem().Set(resultValue) + converted = true + } + } + if converted { + break + } + if resultValue.Kind() == reflect.Pointer { + resultValue = resultValue.Elem() + } else { + break + } + } + + return converted, nil +} diff --git a/util/gconv/gconv_converter_doMapConvert.go b/util/gconv/gconv_converter_doMapConvert.go new file mode 100644 index 000000000..fb33f9658 --- /dev/null +++ b/util/gconv/gconv_converter_doMapConvert.go @@ -0,0 +1,504 @@ +// 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 + +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" + "github.com/gogf/gf/v2/util/gtag" +) + +// MapConvert implements the map converting. +// It automatically checks and converts json string to map if `value` is string/[]byte. +// +// TODO completely implement the recursive converting for all types, especially the map. +func (c *impConverter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { + if value == nil { + return nil + } + // It redirects to its underlying value if it has implemented interface iVal. + if v, ok := value.(localinterface.IVal); ok { + value = v.Val() + } + var ( + usedOption = getUsedMapOption(option...) + newTags = gtag.StructTagPriority + ) + if usedOption.Deep { + recursive = recursiveTypeTrue + } + switch len(usedOption.Tags) { + case 0: + // No need handling. + case 1: + newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) + default: + newTags = append(usedOption.Tags, gtag.StructTagPriority...) + } + // Assert the common combination of types, and finally it uses reflection. + dataMap := make(map[string]interface{}) + switch r := value.(type) { + case string: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { + return nil + } + } else { + return nil + } + case []byte: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { + return nil + } + } else { + return nil + } + case map[interface{}]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[interface{}]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]int: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]uint: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float32: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float64: + for k, v := range r { + dataMap[String(k)] = v + } + case map[string]bool: + for k, v := range r { + dataMap[k] = v + } + case map[string]int: + for k, v := range r { + dataMap[k] = v + } + case map[string]uint: + for k, v := range r { + dataMap[k] = v + } + case map[string]float32: + for k, v := range r { + dataMap[k] = v + } + case map[string]float64: + for k, v := range r { + dataMap[k] = v + } + case map[string]string: + for k, v := range r { + dataMap[k] = v + } + case map[string]interface{}: + if recursive == recursiveTypeTrue { + recursiveOption := usedOption + recursiveOption.Tags = newTags + // A copy of current map. + for k, v := range r { + dataMap[k] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + } else { + // It returns the map directly without any changing. + return r + } + case map[int]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[int]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[uint]string: + for k, v := range r { + dataMap[String(k)] = v + } + + default: + // Not a common type, it then uses reflection for conversion. + var reflectValue reflect.Value + if v, ok := value.(reflect.Value); ok { + reflectValue = v + } else { + reflectValue = reflect.ValueOf(value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + // If `value` is type of array, it converts the value of even number index as its key and + // the value of odd number index as its corresponding value, for example: + // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} + // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} + case reflect.Slice, reflect.Array: + length := reflectValue.Len() + for i := 0; i < length; i += 2 { + if i+1 < length { + dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() + } else { + dataMap[String(reflectValue.Index(i).Interface())] = nil + } + } + case reflect.Map, reflect.Struct, reflect.Interface: + recursiveOption := usedOption + recursiveOption.Tags = newTags + convertedValue := c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: true, + Value: value, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + MustMapReturn: mustMapReturn, + }, + ) + if m, ok := convertedValue.(map[string]interface{}); ok { + return m + } + return nil + default: + return nil + } + } + return dataMap +} + +func getUsedMapOption(option ...MapOption) MapOption { + var usedOption MapOption + if len(option) > 0 { + usedOption = option[0] + } + return usedOption +} + +type doMapConvertForMapOrStructValueInput struct { + IsRoot bool // It returns directly if it is not root and with no recursive converting. + Value interface{} // Current operation value. + RecursiveType recursiveType // The type from top function entry. + RecursiveOption bool // Whether convert recursively for `current` operation. + Option MapOption // Map converting option. + MustMapReturn bool // Must return map instead of Value when empty. +} + +func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { + if !in.IsRoot && !in.RecursiveOption { + return in.Value + } + + var reflectValue reflect.Value + if v, ok := in.Value.(reflect.Value); ok { + reflectValue = v + in.Value = v.Interface() + } else { + reflectValue = reflect.ValueOf(in.Value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Map: + var ( + mapIter = reflectValue.MapRange() + dataMap = make(map[string]interface{}) + ) + for mapIter.Next() { + var ( + mapKeyValue = mapIter.Value() + mapValue interface{} + ) + switch { + case mapKeyValue.IsZero(): + if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { + // quick check for nil value. + mapValue = nil + } else { + // in case of: + // exception recovered: reflect: call of reflect.Value.Interface on zero Value + mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() + } + default: + mapValue = mapKeyValue.Interface() + } + dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapValue, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + return dataMap + + case reflect.Struct: + var dataMap = make(map[string]interface{}) + // Map converting interface check. + if v, ok := in.Value.(localinterface.IMapStrAny); ok { + // Value copy, in case of concurrent safety. + for mapK, mapV := range v.MapStrAny() { + if in.RecursiveOption { + dataMap[mapK] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapV, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } else { + dataMap[mapK] = mapV + } + } + if len(dataMap) > 0 { + return dataMap + } + } + // Using reflect for converting. + var ( + rtField reflect.StructField + rvField reflect.Value + reflectType = reflectValue.Type() // attribute value type. + mapKey = "" // mapKey may be the tag name or the struct attribute name. + ) + for i := 0; i < reflectValue.NumField(); i++ { + rtField = reflectType.Field(i) + rvField = reflectValue.Field(i) + // Only convert the public attributes. + fieldName := rtField.Name + if !utils.IsLetterUpper(fieldName[0]) { + continue + } + mapKey = "" + fieldTag := rtField.Tag + for _, tag := range in.Option.Tags { + if mapKey = fieldTag.Get(tag); mapKey != "" { + break + } + } + if mapKey == "" { + mapKey = fieldName + } else { + // Support json tag feature: -, omitempty + mapKey = strings.TrimSpace(mapKey) + if mapKey == "-" { + continue + } + array := strings.Split(mapKey, ",") + if len(array) > 1 { + switch strings.TrimSpace(array[1]) { + case "omitempty": + if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { + continue + } else { + mapKey = strings.TrimSpace(array[0]) + } + default: + mapKey = strings.TrimSpace(array[0]) + } + } + if mapKey == "" { + mapKey = fieldName + } + } + if in.RecursiveOption || rtField.Anonymous { + // Do map converting recursively. + var ( + rvAttrField = rvField + rvAttrKind = rvField.Kind() + ) + if rvAttrKind == reflect.Ptr { + rvAttrField = rvField.Elem() + rvAttrKind = rvAttrField.Kind() + } + switch rvAttrKind { + case reflect.Struct: + // Embedded struct and has no fields, just ignores it. + // Eg: gmeta.Meta + if rvAttrField.Type().NumField() == 0 { + continue + } + var ( + hasNoTag = mapKey == fieldName + // DO NOT use rvAttrField.Interface() here, + // as it might be changed from pointer to struct. + rvInterface = rvField.Interface() + ) + switch { + case hasNoTag && rtField.Anonymous: + // It means this attribute field has no tag. + // Overwrite the attribute with sub-struct attribute fields. + anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + if m, ok := anonymousValue.(map[string]interface{}); ok { + for k, v := range m { + dataMap[k] = v + } + } else { + dataMap[mapKey] = rvInterface + } + + // It means this attribute field has desired tag. + case !hasNoTag && rtField.Anonymous: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + + default: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + + // The struct attribute is type of slice. + case reflect.Array, reflect.Slice: + length := rvAttrField.Len() + if length == 0 { + dataMap[mapKey] = rvAttrField.Interface() + break + } + array := make([]interface{}, length) + for arrayIndex := 0; arrayIndex < length; arrayIndex++ { + array[arrayIndex] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvAttrField.Index(arrayIndex).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = array + case reflect.Map: + var ( + mapIter = rvAttrField.MapRange() + nestedMap = make(map[string]interface{}) + ) + for mapIter.Next() { + nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapIter.Value().Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = nestedMap + default: + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } else { + // No recursive map value converting + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } + if !in.MustMapReturn && len(dataMap) == 0 { + return in.Value + } + return dataMap + + // The given value is type of slice. + case reflect.Array, reflect.Slice: + length := reflectValue.Len() + if length == 0 { + break + } + array := make([]interface{}, reflectValue.Len()) + for i := 0; i < length; i++ { + array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: reflectValue.Index(i).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + return array + + default: + } + return in.Value +} diff --git a/util/gconv/gconv_converter_float.go b/util/gconv/gconv_converter_float.go index 3c186ab56..d9e5520d6 100644 --- a/util/gconv/gconv_converter_float.go +++ b/util/gconv/gconv_converter_float.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Float32(any any) (float32, error) { +func (c *impConverter) Float32(any any) (float32, error) { if empty.IsNil(any) { return 0, nil } @@ -78,7 +78,7 @@ func (c *Converter) Float32(any any) (float32, error) { } } -func (c *Converter) Float64(any any) (float64, error) { +func (c *impConverter) Float64(any any) (float64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_converter_int.go b/util/gconv/gconv_converter_int.go index cc23f314f..fb742471c 100644 --- a/util/gconv/gconv_converter_int.go +++ b/util/gconv/gconv_converter_int.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Int(any any) (int, error) { +func (c *impConverter) Int(any any) (int, error) { if v, ok := any.(int); ok { return v, nil } @@ -29,7 +29,7 @@ func (c *Converter) Int(any any) (int, error) { return int(v), nil } -func (c *Converter) Int8(any any) (int8, error) { +func (c *impConverter) Int8(any any) (int8, error) { if v, ok := any.(int8); ok { return v, nil } @@ -40,7 +40,7 @@ func (c *Converter) Int8(any any) (int8, error) { return int8(v), nil } -func (c *Converter) Int16(any any) (int16, error) { +func (c *impConverter) Int16(any any) (int16, error) { if v, ok := any.(int16); ok { return v, nil } @@ -51,7 +51,7 @@ func (c *Converter) Int16(any any) (int16, error) { return int16(v), nil } -func (c *Converter) Int32(any any) (int32, error) { +func (c *impConverter) Int32(any any) (int32, error) { if v, ok := any.(int32); ok { return v, nil } @@ -62,7 +62,7 @@ func (c *Converter) Int32(any any) (int32, error) { return int32(v), nil } -func (c *Converter) Int64(any any) (int64, error) { +func (c *impConverter) Int64(any any) (int64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go index 13f7a3d22..60a806e6f 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/gconv_converter_map.go @@ -6,499 +6,492 @@ package gconv -import ( - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" - "github.com/gogf/gf/v2/util/gtag" -) - -// MapConvert implements the map converting. -// It automatically checks and converts json string to map if `value` is string/[]byte. +//// MapStrStr converts `value` to map[string]string. +//// Note that there might be data copy for this map type converting. +//func (c *impConverter) MapStrStr(value any, option ...MapOption) (map[string]string, error) { +// if r, ok := value.(map[string]string); ok { +// return r, nil +// } +// m := Map(value, option...) +// if len(m) > 0 { +// vMap := make(map[string]string, len(m)) +// for k, v := range m { +// s, err := c.String(v) +// if err != nil { +// return nil, err +// } +// vMap[k] = s +// } +// return vMap, nil +// } +// return nil, nil +//} // -// TODO completely implement the recursive converting for all types, especially the map. -func (c *Converter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { - if value == nil { - return nil - } - // It redirects to its underlying value if it has implemented interface iVal. - if v, ok := value.(localinterface.IVal); ok { - value = v.Val() - } - var ( - usedOption = getUsedMapOption(option...) - newTags = gtag.StructTagPriority - ) - if usedOption.Deep { - recursive = recursiveTypeTrue - } - switch len(usedOption.Tags) { - case 0: - // No need handling. - case 1: - newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) - default: - newTags = append(usedOption.Tags, gtag.StructTagPriority...) - } - // Assert the common combination of types, and finally it uses reflection. - dataMap := make(map[string]interface{}) - switch r := value.(type) { - case string: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { - return nil - } - } else { - return nil - } - case []byte: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { - return nil - } - } else { - return nil - } - case map[interface{}]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[interface{}]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]int: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]uint: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float32: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float64: - for k, v := range r { - dataMap[String(k)] = v - } - case map[string]bool: - for k, v := range r { - dataMap[k] = v - } - case map[string]int: - for k, v := range r { - dataMap[k] = v - } - case map[string]uint: - for k, v := range r { - dataMap[k] = v - } - case map[string]float32: - for k, v := range r { - dataMap[k] = v - } - case map[string]float64: - for k, v := range r { - dataMap[k] = v - } - case map[string]string: - for k, v := range r { - dataMap[k] = v - } - case map[string]interface{}: - if recursive == recursiveTypeTrue { - recursiveOption := usedOption - recursiveOption.Tags = newTags - // A copy of current map. - for k, v := range r { - dataMap[k] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - } else { - // It returns the map directly without any changing. - return r - } - case map[int]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[int]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[uint]string: - for k, v := range r { - dataMap[String(k)] = v - } - - default: - // Not a common type, it then uses reflection for conversion. - var reflectValue reflect.Value - if v, ok := value.(reflect.Value); ok { - reflectValue = v - } else { - reflectValue = reflect.ValueOf(value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - // If `value` is type of array, it converts the value of even number index as its key and - // the value of odd number index as its corresponding value, for example: - // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} - // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} - case reflect.Slice, reflect.Array: - length := reflectValue.Len() - for i := 0; i < length; i += 2 { - if i+1 < length { - dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() - } else { - dataMap[String(reflectValue.Index(i).Interface())] = nil - } - } - case reflect.Map, reflect.Struct, reflect.Interface: - recursiveOption := usedOption - recursiveOption.Tags = newTags - convertedValue := c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: true, - Value: value, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - MustMapReturn: mustMapReturn, - }, - ) - if m, ok := convertedValue.(map[string]interface{}); ok { - return m - } - return nil - default: - return nil - } - } - return dataMap -} - -func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption - if len(option) > 0 { - usedOption = option[0] - } - return usedOption -} - -type doMapConvertForMapOrStructValueInput struct { - IsRoot bool // It returns directly if it is not root and with no recursive converting. - Value interface{} // Current operation value. - RecursiveType recursiveType // The type from top function entry. - RecursiveOption bool // Whether convert recursively for `current` operation. - Option MapOption // Map converting option. - MustMapReturn bool // Must return map instead of Value when empty. -} - -func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { - if !in.IsRoot && !in.RecursiveOption { - return in.Value - } - - var reflectValue reflect.Value - if v, ok := in.Value.(reflect.Value); ok { - reflectValue = v - in.Value = v.Interface() - } else { - reflectValue = reflect.ValueOf(in.Value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - case reflect.Map: - var ( - mapIter = reflectValue.MapRange() - dataMap = make(map[string]interface{}) - ) - for mapIter.Next() { - var ( - mapKeyValue = mapIter.Value() - mapValue interface{} - ) - switch { - case mapKeyValue.IsZero(): - if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { - // quick check for nil value. - mapValue = nil - } else { - // in case of: - // exception recovered: reflect: call of reflect.Value.Interface on zero Value - mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() - } - default: - mapValue = mapKeyValue.Interface() - } - dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapValue, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - return dataMap - - case reflect.Struct: - var dataMap = make(map[string]interface{}) - // Map converting interface check. - if v, ok := in.Value.(localinterface.IMapStrAny); ok { - // Value copy, in case of concurrent safety. - for mapK, mapV := range v.MapStrAny() { - if in.RecursiveOption { - dataMap[mapK] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapV, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } else { - dataMap[mapK] = mapV - } - } - if len(dataMap) > 0 { - return dataMap - } - } - // Using reflect for converting. - var ( - rtField reflect.StructField - rvField reflect.Value - reflectType = reflectValue.Type() // attribute value type. - mapKey = "" // mapKey may be the tag name or the struct attribute name. - ) - for i := 0; i < reflectValue.NumField(); i++ { - rtField = reflectType.Field(i) - rvField = reflectValue.Field(i) - // Only convert the public attributes. - fieldName := rtField.Name - if !utils.IsLetterUpper(fieldName[0]) { - continue - } - mapKey = "" - fieldTag := rtField.Tag - for _, tag := range in.Option.Tags { - if mapKey = fieldTag.Get(tag); mapKey != "" { - break - } - } - if mapKey == "" { - mapKey = fieldName - } else { - // Support json tag feature: -, omitempty - mapKey = strings.TrimSpace(mapKey) - if mapKey == "-" { - continue - } - array := strings.Split(mapKey, ",") - if len(array) > 1 { - switch strings.TrimSpace(array[1]) { - case "omitempty": - if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { - continue - } else { - mapKey = strings.TrimSpace(array[0]) - } - default: - mapKey = strings.TrimSpace(array[0]) - } - } - if mapKey == "" { - mapKey = fieldName - } - } - if in.RecursiveOption || rtField.Anonymous { - // Do map converting recursively. - var ( - rvAttrField = rvField - rvAttrKind = rvField.Kind() - ) - if rvAttrKind == reflect.Ptr { - rvAttrField = rvField.Elem() - rvAttrKind = rvAttrField.Kind() - } - switch rvAttrKind { - case reflect.Struct: - // Embedded struct and has no fields, just ignores it. - // Eg: gmeta.Meta - if rvAttrField.Type().NumField() == 0 { - continue - } - var ( - hasNoTag = mapKey == fieldName - // DO NOT use rvAttrField.Interface() here, - // as it might be changed from pointer to struct. - rvInterface = rvField.Interface() - ) - switch { - case hasNoTag && rtField.Anonymous: - // It means this attribute field has no tag. - // Overwrite the attribute with sub-struct attribute fields. - anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - if m, ok := anonymousValue.(map[string]interface{}); ok { - for k, v := range m { - dataMap[k] = v - } - } else { - dataMap[mapKey] = rvInterface - } - - // It means this attribute field has desired tag. - case !hasNoTag && rtField.Anonymous: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - - default: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - - // The struct attribute is type of slice. - case reflect.Array, reflect.Slice: - length := rvAttrField.Len() - if length == 0 { - dataMap[mapKey] = rvAttrField.Interface() - break - } - array := make([]interface{}, length) - for arrayIndex := 0; arrayIndex < length; arrayIndex++ { - array[arrayIndex] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvAttrField.Index(arrayIndex).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = array - case reflect.Map: - var ( - mapIter = rvAttrField.MapRange() - nestedMap = make(map[string]interface{}) - ) - for mapIter.Next() { - nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapIter.Value().Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = nestedMap - default: - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } else { - // No recursive map value converting - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } - if !in.MustMapReturn && len(dataMap) == 0 { - return in.Value - } - return dataMap - - // The given value is type of slice. - case reflect.Array, reflect.Slice: - length := reflectValue.Len() - if length == 0 { - break - } - array := make([]interface{}, reflectValue.Len()) - for i := 0; i < length; i++ { - array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: reflectValue.Index(i).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - return array - - default: - } - return in.Value -} +//// Map implements the map converting. +//// It automatically checks and converts json string to map if `value` is string/[]byte. +//// +//// TODO completely implement the recursive converting for all types, especially the map. +//func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { +// if value == nil { +// return nil, nil +// } +// // It redirects to its underlying value if it has implemented interface iVal. +// if v, ok := value.(localinterface.IVal); ok { +// value = v.Val() +// } +// var ( +// newTags = gtag.StructTagPriority +// ) +// switch len(option.Tags) { +// case 0: +// // No need handling. +// case 1: +// newTags = append(strings.Split(option.Tags[0], ","), gtag.StructTagPriority...) +// default: +// newTags = append(option.Tags, gtag.StructTagPriority...) +// } +// // Assert the common combination of types, and finally it uses reflection. +// dataMap := make(map[string]any) +// switch r := value.(type) { +// case string: +// // If it is a JSON string, automatically unmarshal it! +// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { +// if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { +// return nil, err +// } +// } else { +// return nil, nil +// } +// case []byte: +// // If it is a JSON string, automatically unmarshal it! +// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { +// if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { +// return nil, err +// } +// } else { +// return nil, nil +// } +// case map[any]any: +// recursiveOption := option +// recursiveOption.Tags = newTags +// for k, v := range r { +// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// case map[any]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]int: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]uint: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]float32: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]float64: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[string]bool: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]int: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]uint: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]float32: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]float64: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]string: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]any: +// if option.Deep { +// recursiveOption := option +// recursiveOption.Tags = newTags +// // A copy of current map. +// for k, v := range r { +// dataMap[k] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// } else { +// // It returns the map directly without any changing. +// return r, nil +// } +// case map[int]any: +// recursiveOption := option +// recursiveOption.Tags = newTags +// for k, v := range r { +// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// case map[int]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[uint]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// +// default: +// // Not a common type, it then uses reflection for conversion. +// var reflectValue reflect.Value +// if v, ok := value.(reflect.Value); ok { +// reflectValue = v +// } else { +// reflectValue = reflect.ValueOf(value) +// } +// reflectKind := reflectValue.Kind() +// // If it is a pointer, we should find its real data type. +// for reflectKind == reflect.Ptr { +// reflectValue = reflectValue.Elem() +// reflectKind = reflectValue.Kind() +// } +// switch reflectKind { +// // If `value` is type of array, it converts the value of even number index as its key and +// // the value of odd number index as its corresponding value, for example: +// // []string{"k1","v1","k2","v2"} => map[string]any{"k1":"v1", "k2":"v2"} +// // []string{"k1","v1","k2"} => map[string]any{"k1":"v1", "k2":nil} +// case reflect.Slice, reflect.Array: +// length := reflectValue.Len() +// for i := 0; i < length; i += 2 { +// if i+1 < length { +// dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() +// } else { +// dataMap[String(reflectValue.Index(i).Interface())] = nil +// } +// } +// case reflect.Map, reflect.Struct, reflect.Interface: +// recursiveOption := option +// recursiveOption.Tags = newTags +// convertedValue := c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: true, +// Value: value, +// Recursive: option.Deep, +// Option: recursiveOption, +// MustMapReturn: option.EmptyEvenNil, +// }, +// ) +// if m, ok := convertedValue.(map[string]any); ok { +// return m, nil +// } +// return nil, nil +// default: +// return nil, nil +// } +// } +// return dataMap, nil +//} +// +//func getUsedMapOption(option ...MapOption) MapOption { +// var usedOption MapOption +// if len(option) > 0 { +// usedOption = option[0] +// } +// return usedOption +//} +// +//type doMapConvertForMapOrStructValueInput struct { +// IsRoot bool // It returns directly if it is not root and with no recursive converting. +// Value any // Current operation value. +// Recursive bool // Whether convert recursively for `current` operation. +// Option MapOption // Map converting option. +// MustMapReturn bool // Must return map instead of Value when empty. +//} +// +//func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) any { +// if !in.IsRoot && !in.Recursive { +// return in.Value +// } +// +// var reflectValue reflect.Value +// if v, ok := in.Value.(reflect.Value); ok { +// reflectValue = v +// in.Value = v.Interface() +// } else { +// reflectValue = reflect.ValueOf(in.Value) +// } +// reflectKind := reflectValue.Kind() +// // If it is a pointer, we should find its real data type. +// for reflectKind == reflect.Ptr { +// reflectValue = reflectValue.Elem() +// reflectKind = reflectValue.Kind() +// } +// switch reflectKind { +// case reflect.Map: +// var ( +// mapIter = reflectValue.MapRange() +// dataMap = make(map[string]any) +// ) +// for mapIter.Next() { +// var ( +// mapKeyValue = mapIter.Value() +// mapValue any +// ) +// switch { +// case mapKeyValue.IsZero(): +// if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { +// // quick check for nil value. +// mapValue = nil +// } else { +// // in case of: +// // exception recovered: reflect: call of reflect.Value.Interface on zero Value +// mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() +// } +// default: +// mapValue = mapKeyValue.Interface() +// } +// dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapValue, +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// return dataMap +// +// case reflect.Struct: +// var dataMap = make(map[string]any) +// // Map converting interface check. +// if v, ok := in.Value.(localinterface.IMapStrAny); ok { +// // Value copy, in case of concurrent safety. +// for mapK, mapV := range v.MapStrAny() { +// if in.Recursive { +// dataMap[mapK] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapV, +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } else { +// dataMap[mapK] = mapV +// } +// } +// if len(dataMap) > 0 { +// return dataMap +// } +// } +// // Using reflect for converting. +// var ( +// rtField reflect.StructField +// rvField reflect.Value +// reflectType = reflectValue.Type() // attribute value type. +// mapKey = "" // mapKey may be the tag name or the struct attribute name. +// ) +// for i := 0; i < reflectValue.NumField(); i++ { +// rtField = reflectType.Field(i) +// rvField = reflectValue.Field(i) +// // Only convert the public attributes. +// fieldName := rtField.Name +// if !utils.IsLetterUpper(fieldName[0]) { +// continue +// } +// mapKey = "" +// fieldTag := rtField.Tag +// for _, tag := range in.Option.Tags { +// if mapKey = fieldTag.Get(tag); mapKey != "" { +// break +// } +// } +// if mapKey == "" { +// mapKey = fieldName +// } else { +// // Support json tag feature: -, omitempty +// mapKey = strings.TrimSpace(mapKey) +// if mapKey == "-" { +// continue +// } +// array := strings.Split(mapKey, ",") +// if len(array) > 1 { +// switch strings.TrimSpace(array[1]) { +// case "omitempty": +// if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { +// continue +// } else { +// mapKey = strings.TrimSpace(array[0]) +// } +// default: +// mapKey = strings.TrimSpace(array[0]) +// } +// } +// if mapKey == "" { +// mapKey = fieldName +// } +// } +// if in.Recursive || rtField.Anonymous { +// // Do map converting recursively. +// var ( +// rvAttrField = rvField +// rvAttrKind = rvField.Kind() +// ) +// if rvAttrKind == reflect.Ptr { +// rvAttrField = rvField.Elem() +// rvAttrKind = rvAttrField.Kind() +// } +// switch rvAttrKind { +// case reflect.Struct: +// // Embedded struct and has no fields, just ignores it. +// // Eg: gmeta.Meta +// if rvAttrField.Type().NumField() == 0 { +// continue +// } +// var ( +// hasNoTag = mapKey == fieldName +// // DO NOT use rvAttrField.Interface() here, +// // as it might be changed from pointer to struct. +// rvInterface = rvField.Interface() +// ) +// switch { +// case hasNoTag && rtField.Anonymous: +// // It means this attribute field has no tag. +// // Overwrite the attribute with sub-struct attribute fields. +// anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: true, +// Option: in.Option, +// }) +// if m, ok := anonymousValue.(map[string]any); ok { +// for k, v := range m { +// dataMap[k] = v +// } +// } else { +// dataMap[mapKey] = rvInterface +// } +// +// // It means this attribute field has desired tag. +// case !hasNoTag && rtField.Anonymous: +// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: true, +// Option: in.Option, +// }) +// +// default: +// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: in.Recursive, +// Option: in.Option, +// }) +// } +// +// // The struct attribute is type of slice. +// case reflect.Array, reflect.Slice: +// length := rvAttrField.Len() +// if length == 0 { +// dataMap[mapKey] = rvAttrField.Interface() +// break +// } +// array := make([]any, length) +// for arrayIndex := 0; arrayIndex < length; arrayIndex++ { +// array[arrayIndex] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvAttrField.Index(arrayIndex).Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// dataMap[mapKey] = array +// case reflect.Map: +// var ( +// mapIter = rvAttrField.MapRange() +// nestedMap = make(map[string]any) +// ) +// for mapIter.Next() { +// nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapIter.Value().Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// dataMap[mapKey] = nestedMap +// default: +// if rvField.IsValid() { +// dataMap[mapKey] = reflectValue.Field(i).Interface() +// } else { +// dataMap[mapKey] = nil +// } +// } +// } else { +// // No recursive map value converting +// if rvField.IsValid() { +// dataMap[mapKey] = reflectValue.Field(i).Interface() +// } else { +// dataMap[mapKey] = nil +// } +// } +// } +// if !in.MustMapReturn && len(dataMap) == 0 { +// return in.Value +// } +// return dataMap +// +// // The given value is type of slice. +// case reflect.Array, reflect.Slice: +// length := reflectValue.Len() +// if length == 0 { +// break +// } +// array := make([]any, reflectValue.Len()) +// for i := 0; i < length; i++ { +// array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: reflectValue.Index(i).Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }) +// } +// return array +// +// default: +// } +// return in.Value +//} diff --git a/util/gconv/gconv_converter_maps.go b/util/gconv/gconv_converter_maps.go deleted file mode 100644 index a5c4126a5..000000000 --- a/util/gconv/gconv_converter_maps.go +++ /dev/null @@ -1,7 +0,0 @@ -// 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 diff --git a/util/gconv/gconv_converter_maptomap.go b/util/gconv/gconv_converter_maptomap.go index 46a6bf879..5026ce223 100644 --- a/util/gconv/gconv_converter_maptomap.go +++ b/util/gconv/gconv_converter_maptomap.go @@ -23,7 +23,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the items of original map `params` is type struct. -func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { +func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { var ( paramsRv reflect.Value paramsKind reflect.Kind @@ -98,27 +98,27 @@ func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]stri return err } default: - mapValue.Set( - reflect.ValueOf( - c.doConvert(doConvertInput{ - FromValue: paramsRv.MapIndex(key).Interface(), - ToTypeName: pointerValueType.String(), - ReferValue: mapValue, - Extra: nil, - }), - ), - ) + convertResult, err := c.doConvert(doConvertInput{ + FromValue: paramsRv.MapIndex(key).Interface(), + ToTypeName: pointerValueType.String(), + ReferValue: mapValue, + Extra: nil, + }) + if err != nil { + return err + } + mapValue.Set(reflect.ValueOf(convertResult)) } - var mapKey = reflect.ValueOf( - c.doConvert( - doConvertInput{ - FromValue: key.Interface(), - ToTypeName: pointerKeyType.Name(), - ReferValue: reflect.New(pointerKeyType).Elem().Interface(), - Extra: nil, - }, - ), - ) + convertResult, err := c.doConvert(doConvertInput{ + FromValue: key.Interface(), + ToTypeName: pointerKeyType.Name(), + ReferValue: reflect.New(pointerKeyType).Elem().Interface(), + Extra: nil, + }) + if err != nil { + return err + } + var mapKey = reflect.ValueOf(convertResult) dataMap.SetMapIndex(mapKey, mapValue) } pointerRv.Set(dataMap) diff --git a/util/gconv/gconv_converter_maptomaps.go b/util/gconv/gconv_converter_maptomaps.go index 2c33ebfdc..9783a4e6f 100644 --- a/util/gconv/gconv_converter_maptomaps.go +++ b/util/gconv/gconv_converter_maptomaps.go @@ -21,7 +21,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the item of `params` is type struct. -func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { +func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { // Params and its element type check. var ( paramsRv reflect.Value diff --git a/util/gconv/gconv_converter_rune.go b/util/gconv/gconv_converter_rune.go index b5bff899e..0a6c5fdca 100644 --- a/util/gconv/gconv_converter_rune.go +++ b/util/gconv/gconv_converter_rune.go @@ -6,7 +6,7 @@ package gconv -func (c *Converter) Rune(any any) (rune, error) { +func (c *impConverter) Rune(any any) (rune, error) { if v, ok := any.(rune); ok { return v, nil } @@ -17,7 +17,7 @@ func (c *Converter) Rune(any any) (rune, error) { return v, nil } -func (c *Converter) Runes(any any) ([]rune, error) { +func (c *impConverter) Runes(any any) ([]rune, error) { if v, ok := any.([]rune); ok { return v, nil } diff --git a/util/gconv/gconv_converter_scan.go b/util/gconv/gconv_converter_scan.go index 269b3de94..ccd012e78 100644 --- a/util/gconv/gconv_converter_scan.go +++ b/util/gconv/gconv_converter_scan.go @@ -15,7 +15,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { +func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { return nil @@ -182,7 +182,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[ // - dstPointer: The destination pointer to convert to // - dstPointerReflectType: The reflection type of the destination pointer // - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names -func (c *Converter) doScanForComplicatedTypes( +func (c *impConverter) doScanForComplicatedTypes( srcValue, dstPointer any, dstPointerReflectType reflect.Type, paramKeyToAttrMap ...map[string]string, diff --git a/util/gconv/gconv_converter_slice_any.go b/util/gconv/gconv_converter_slice_any.go new file mode 100644 index 000000000..d9d0c2a62 --- /dev/null +++ b/util/gconv/gconv_converter_slice_any.go @@ -0,0 +1,142 @@ +// 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 + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +type SliceOption struct { + // FailBreak specifies whether to break converting the next element + // if one element conversion fails in slice. + FailBreak bool +} + +// SliceAny converts `any` to []any. +func (c *impConverter) SliceAny(any interface{}, option SliceOption) ([]any, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + array []interface{} + ) + switch value := any.(type) { + case []interface{}: + array = value + case []string: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int8: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int16: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int32: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + + case []uint16: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint32: + for _, v := range value { + array = append(array, v) + } + case []uint64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []bool: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []float32: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []float64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return v.Interfaces(), err + } + + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]interface{}, length) + ) + for i := 0; i < length; i++ { + slice[i] = originValueAndKind.OriginValue.Index(i).Interface() + } + return slice, err + + default: + return []interface{}{any}, err + } +} diff --git a/util/gconv/gconv_converter_slice_float.go b/util/gconv/gconv_converter_slice_float.go new file mode 100644 index 000000000..201e927f7 --- /dev/null +++ b/util/gconv/gconv_converter_slice_float.go @@ -0,0 +1,417 @@ +// 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 + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceFloat32 converts `any` to []float32. +func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + f float32 + array []float32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int8: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int16: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int32: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []float32{}, err + } + if utils.IsNumeric(value) { + f, err = c.Float32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []float32{f}, err + } + case []uint16: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint32: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []bool: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float32: + array = value + case []float64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []interface{}: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IFloats); ok { + return c.SliceFloat32(v.Floats(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceFloat32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]float32, length) + ) + for i := 0; i < length; i++ { + f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = f + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []float32{}, err + } + f, err = c.Float32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []float32{f}, err + } +} + +// SliceFloat64 converts `any` to []float64. +func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + f float64 + array []float64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int8: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int16: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int64: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []float64{}, err + } + if utils.IsNumeric(value) { + f, err = c.Float64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []float64{f}, err + } + case []uint16: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint64: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []bool: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float64: + array = value + case []interface{}: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IFloats); ok { + return v.Floats(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceFloat64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]float64, length) + ) + for i := 0; i < length; i++ { + f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = f + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []float64{}, err + } + f, err = c.Float64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []float64{f}, err + } +} diff --git a/util/gconv/gconv_converter_slice_int.go b/util/gconv/gconv_converter_slice_int.go new file mode 100644 index 000000000..4dcc6cc8d --- /dev/null +++ b/util/gconv/gconv_converter_slice_int.go @@ -0,0 +1,536 @@ +// 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 + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceInt converts `any` to []int. +func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int + array []int = nil + ) + switch value := any.(type) { + case []string: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = value + case []int8: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int16: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int32: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int64: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int{ii}, err + } + case []uint16: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint32: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint64: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []bool: + array = make([]int, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return v.Ints(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int{}, err + } + ii, err = c.Int(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int{ii}, err + } +} + +// SliceInt32 converts `any` to []int32. +func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int32 + array []int32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int8: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int16: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int32: + array = value + case []int64: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int32{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int32{ii}, err + } + case []uint16: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint32: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint64: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []bool: + array = make([]int32, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return c.SliceInt32(v.Ints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int32, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int32{}, err + } + ii, err = c.Int32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int32{ii}, err + } +} + +// SliceInt64 converts `any` to []int64. +func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int64 + array []int64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int8: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int16: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int32: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int64: + array = value + case []uint: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int64{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int64{ii}, err + } + case []uint16: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint32: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint64: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []bool: + array = make([]int64, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return c.SliceInt64(v.Ints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int64, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int64{}, err + } + ii, err = c.Int64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int64{ii}, err + } +} diff --git a/util/gconv/gconv_converter_slice_map.go b/util/gconv/gconv_converter_slice_map.go new file mode 100644 index 000000000..813833196 --- /dev/null +++ b/util/gconv/gconv_converter_slice_map.go @@ -0,0 +1,59 @@ +// 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 + +import "github.com/gogf/gf/v2/internal/json" + +// SliceMap converts `value` to []map[string]any. +// Note that it automatically checks and converts json string to []map if `value` is string/[]byte. +func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) { + if value == nil { + return nil, nil + } + switch r := value.(type) { + case string: + list := make([]map[string]any, 0) + if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { + if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil { + return nil, err + } + return list, nil + } + return nil, nil + + case []byte: + list := make([]map[string]any, 0) + if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { + if err := json.UnmarshalUseNumber(r, &list); err != nil { + return nil, err + } + return list, nil + } + return nil, nil + + case []map[string]any: + return r, nil + + default: + array, err := c.SliceAny(value, sliceOption) + if err != nil { + return nil, err + } + if len(array) == 0 { + return nil, nil + } + list := make([]map[string]any, len(array)) + for k, v := range array { + m := Map(v, mapOption) + //if err != nil { + // return nil, err + //} + list[k] = m + } + return list, nil + } +} diff --git a/util/gconv/gconv_converter_slice_str.go b/util/gconv/gconv_converter_slice_str.go new file mode 100644 index 000000000..5f454b0eb --- /dev/null +++ b/util/gconv/gconv_converter_slice_str.go @@ -0,0 +1,216 @@ +// 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 + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceStr converts `any` to []string. +func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + s string + array []string = nil + ) + switch value := any.(type) { + case []int: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int8: + array = make([]string, len(value)) + for k, v := range value { + array[k] = String(v) + } + case []int16: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + return array, err + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []string{}, err + } + return []string{value}, err + case []uint16: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []bool: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []float32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []float64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []interface{}: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []string: + array = value + case [][]byte: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IStrings); ok { + return v.Strings(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceStr(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]string, length) + ) + for i := 0; i < length; i++ { + s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = s + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []string{}, err + } + s, err = c.String(any) + if err != nil && option.FailBreak { + return nil, err + } + return []string{s}, err + } +} diff --git a/util/gconv/gconv_converter_slice_uint.go b/util/gconv/gconv_converter_slice_uint.go new file mode 100644 index 000000000..925c163a6 --- /dev/null +++ b/util/gconv/gconv_converter_slice_uint.go @@ -0,0 +1,527 @@ +// 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 + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceUint converts `any` to []uint. +func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint + array []uint = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int16: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int32: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int64: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint: + array = value + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint{ui}, err + } + case []uint16: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint32: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint64: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []bool: + array = make([]uint, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + + if array != nil { + return array, err + } + + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return v.Uints(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint{}, err + } + ui, err = c.Uint(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint{ui}, err + } +} + +// SliceUint32 converts `any` to []uint32. +func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint32 + array []uint32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int16: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int32: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int64: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint32{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint32{ui}, err + } + case []uint16: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint32: + array = value + case []uint64: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []bool: + array = make([]uint32, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + if array != nil { + return array, err + } + + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return c.SliceUint32(v.Uints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint32, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint32{}, err + } + ui, err = c.Uint32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint32{ui}, err + } +} + +// SliceUint64 converts `any` to []uint64. +func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint64 + array []uint64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int16: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int32: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int64: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint64{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint64{ui}, err + } + case []uint16: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint32: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint64: + array = value + case []bool: + array = make([]uint64, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + if array != nil { + return array, err + } + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return c.SliceUint64(v.Uints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint64, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint64{}, err + } + ui, err = c.Uint64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint64{ui}, err + } +} diff --git a/util/gconv/gconv_converter_string.go b/util/gconv/gconv_converter_string.go index 07e60247b..dd38ac119 100644 --- a/util/gconv/gconv_converter_string.go +++ b/util/gconv/gconv_converter_string.go @@ -20,7 +20,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) String(any any) (string, error) { +func (c *impConverter) String(any any) (string, error) { if empty.IsNil(any) { return "", nil } diff --git a/util/gconv/gconv_converter_struct.go b/util/gconv/gconv_converter_struct.go index 74f21c0bf..ab254be31 100644 --- a/util/gconv/gconv_converter_struct.go +++ b/util/gconv/gconv_converter_struct.go @@ -20,7 +20,7 @@ import ( ) // Struct is the core internal converting function for any data to struct. -func (c *Converter) Struct( +func (c *impConverter) Struct( params any, pointer any, paramKeyToAttrMap map[string]string, @@ -147,7 +147,7 @@ func (c *Converter) Struct( return nil } // Get struct info from cache or parse struct and cache the struct info. - cachedStructInfo := c.internalConvertConfig.GetCachedStructInfo( + cachedStructInfo := c.internalConverter.GetCachedStructInfo( pointerElemReflectValue.Type(), priorityTag, ) // Nothing to be converted. @@ -204,7 +204,7 @@ func (c *Converter) Struct( ) } -func (c *Converter) setOtherSameNameField( +func (c *impConverter) setOtherSameNameField( cachedFieldInfo *structcache.CachedFieldInfo, srcValue any, structValue reflect.Value, @@ -220,7 +220,7 @@ func (c *Converter) setOtherSameNameField( return nil } -func (c *Converter) bindStructWithLoopFieldInfos( +func (c *impConverter) bindStructWithLoopFieldInfos( paramsMap map[string]any, structValue reflect.Value, paramKeyToAttrMap map[string]string, @@ -316,7 +316,7 @@ func fuzzyMatchingFieldName( // bindVarToStructField sets value to struct object attribute by name. // each value to attribute converting comes into in this function. -func (c *Converter) bindVarToStructField( +func (c *impConverter) bindVarToStructField( cachedFieldInfo *structcache.CachedFieldInfo, fieldValue reflect.Value, srcValue any, @@ -439,7 +439,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a } // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func (c *Converter) bindVarToReflectValue( +func (c *impConverter) bindVarToReflectValue( structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, ) (err error) { // JSON content converting. diff --git a/util/gconv/gconv_converter_structs.go b/util/gconv/gconv_converter_structs.go index 347cd5cbd..dc722385d 100644 --- a/util/gconv/gconv_converter_structs.go +++ b/util/gconv/gconv_converter_structs.go @@ -20,7 +20,7 @@ import ( // The parameter `pointer` should be type of pointer to slice of struct. // Note that if `pointer` is a pointer to another pointer of type of slice of struct, // it will create the struct/pointer internally. -func (c *Converter) Structs( +func (c *impConverter) Structs( params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string, ) (err error) { defer func() { diff --git a/util/gconv/gconv_converter_time.go b/util/gconv/gconv_converter_time.go index f1b185758..974daf451 100644 --- a/util/gconv/gconv_converter_time.go +++ b/util/gconv/gconv_converter_time.go @@ -16,7 +16,7 @@ import ( ) // Time converts `any` to time.Time. -func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { +func (c *impConverter) Time(any interface{}, format ...string) (time.Time, error) { // It's already this type. if len(format) == 0 { if v, ok := any.(time.Time); ok { @@ -36,7 +36,7 @@ func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { // Duration converts `any` to time.Duration. // If `any` is string, then it uses time.ParseDuration to convert it. // If `any` is numeric, then it converts `any` as nanoseconds. -func (c *Converter) Duration(any interface{}) (time.Duration, error) { +func (c *impConverter) Duration(any interface{}) (time.Duration, error) { // It's already this type. if v, ok := any.(time.Duration); ok { return v, nil @@ -60,7 +60,7 @@ func (c *Converter) Duration(any interface{}) (time.Duration, error) { // It returns the converted value that matched the first format of the formats slice. // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. -func (c *Converter) GTime(any interface{}, format ...string) (*gtime.Time, error) { +func (c *impConverter) GTime(any interface{}, format ...string) (*gtime.Time, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/gconv_converter_uint.go b/util/gconv/gconv_converter_uint.go index a17ef2a7a..90691feed 100644 --- a/util/gconv/gconv_converter_uint.go +++ b/util/gconv/gconv_converter_uint.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Uint(any any) (uint, error) { +func (c *impConverter) Uint(any any) (uint, error) { if empty.IsNil(any) { return 0, nil } @@ -29,7 +29,7 @@ func (c *Converter) Uint(any any) (uint, error) { return uint(v), err } -func (c *Converter) Uint8(any any) (uint8, error) { +func (c *impConverter) Uint8(any any) (uint8, error) { if empty.IsNil(any) { return 0, nil } @@ -40,7 +40,7 @@ func (c *Converter) Uint8(any any) (uint8, error) { return uint8(v), err } -func (c *Converter) Uint16(any any) (uint16, error) { +func (c *impConverter) Uint16(any any) (uint16, error) { if empty.IsNil(any) { return 0, nil } @@ -51,7 +51,7 @@ func (c *Converter) Uint16(any any) (uint16, error) { return uint16(v), err } -func (c *Converter) Uint32(any any) (uint32, error) { +func (c *impConverter) Uint32(any any) (uint32, error) { if empty.IsNil(any) { return 0, nil } @@ -62,7 +62,7 @@ func (c *Converter) Uint32(any any) (uint32, error) { return uint32(v), err } -func (c *Converter) Uint64(any any) (uint64, error) { +func (c *impConverter) Uint64(any any) (uint64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index 12de2ae30..94436f2f2 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -6,17 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceAny is alias of Interfaces. func SliceAny(any interface{}) []interface{} { return Interfaces(any) @@ -24,123 +13,6 @@ func SliceAny(any interface{}) []interface{} { // Interfaces converts `any` to []interface{}. func Interfaces(any interface{}) []interface{} { - if empty.IsNil(any) { - return nil - } - var array []interface{} - switch value := any.(type) { - case []interface{}: - array = value - case []string: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int8: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int16: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int32: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - - case []uint16: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint32: - for _, v := range value { - array = append(array, v) - } - case []uint64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []bool: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []float32: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []float64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInterfaces); ok { - return v.Interfaces() - } - - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]interface{}, length) - ) - for i := 0; i < length; i++ { - slice[i] = originValueAndKind.OriginValue.Index(i).Interface() - } - return slice - - default: - return []interface{}{any} - } + result, _ := defaultConverter.SliceAny(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index 9d23d7002..7803f2f46 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -6,18 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceFloat is alias of Floats. func SliceFloat(any interface{}) []float64 { return Floats(any) @@ -40,270 +28,12 @@ func Floats(any interface{}) []float64 { // Float32s converts `any` to []float32. func Float32s(any interface{}) []float32 { - if empty.IsNil(any) { - return nil - } - var ( - array []float32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int8: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int16: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int32: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint: - for _, v := range value { - array = append(array, Float32(v)) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []float32{} - } - if utils.IsNumeric(value) { - return []float32{Float32(value)} - } - case []uint16: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint32: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []bool: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []float32: - array = value - case []float64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []interface{}: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IFloats); ok { - return Float32s(v.Floats()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Float32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]float32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Float32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []float32{} - } - return []float32{Float32(any)} - } + result, _ := defaultConverter.SliceFloat32(any, SliceOption{}) + return result } // Float64s converts `any` to []float64. func Float64s(any interface{}) []float64 { - if empty.IsNil(any) { - return nil - } - var ( - array []float64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int8: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int16: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int64: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint: - for _, v := range value { - array = append(array, Float64(v)) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []float64{} - } - if utils.IsNumeric(value) { - return []float64{Float64(value)} - } - case []uint16: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint64: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []bool: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []float32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []float64: - array = value - case []interface{}: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IFloats); ok { - return v.Floats() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Floats(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]float64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Float64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []float64{} - } - return []float64{Float64(any)} - } + result, _ := defaultConverter.SliceFloat64(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index 4b2931e08..adc48bf03 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -6,464 +6,35 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceInt is alias of Ints. -func SliceInt(any interface{}) []int { +func SliceInt(any any) []int { return Ints(any) } // SliceInt32 is alias of Int32s. -func SliceInt32(any interface{}) []int32 { +func SliceInt32(any any) []int32 { return Int32s(any) } // SliceInt64 is alias of Int64s. -func SliceInt64(any interface{}) []int64 { +func SliceInt64(any any) []int64 { return Int64s(any) } // Ints converts `any` to []int. -func Ints(any interface{}) []int { - if empty.IsNil(any) { - return nil - } - var ( - array []int = nil - ) - switch value := any.(type) { - case []string: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []int: - array = value - case []int8: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int16: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int{} - } - if utils.IsNumeric(value) { - return []int{Int(value)} - } - case []uint16: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []bool: - array = make([]int, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []float64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []interface{}: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case [][]byte: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return v.Ints() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Ints(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int{} - } - return []int{Int(any)} - } +func Ints(any any) []int { + result, _ := defaultConverter.SliceInt(any, SliceOption{}) + return result } // Int32s converts `any` to []int32. -func Int32s(any interface{}) []int32 { - if empty.IsNil(any) { - return nil - } - var ( - array []int32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []int: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int8: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int16: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int32: - array = value - case []int64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int32{} - } - if utils.IsNumeric(value) { - return []int32{Int32(value)} - } - case []uint16: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint32: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []bool: - array = make([]int32, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []float64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []interface{}: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case [][]byte: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return Int32s(v.Ints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Int32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int32{} - } - return []int32{Int32(any)} - } +func Int32s(any any) []int32 { + result, _ := defaultConverter.SliceInt32(any, SliceOption{}) + return result } // Int64s converts `any` to []int64. -func Int64s(any interface{}) []int64 { - if empty.IsNil(any) { - return nil - } - var ( - array []int64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []int: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int8: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int16: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int64: - array = value - case []uint: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int64{} - } - if utils.IsNumeric(value) { - return []int64{Int64(value)} - } - case []uint16: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint64: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []bool: - array = make([]int64, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []float64: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []interface{}: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case [][]byte: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return Int64s(v.Ints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Int64s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int64{} - } - return []int64{Int64(any)} - } +func Int64s(any any) []int64 { + result, _ := defaultConverter.SliceInt64(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index ff2157b3c..05ee6d02d 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -6,17 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceStr is alias of Strings. func SliceStr(any interface{}) []string { return Strings(any) @@ -24,140 +13,6 @@ func SliceStr(any interface{}) []string { // Strings converts `any` to []string. func Strings(any interface{}) []string { - if empty.IsNil(any) { - return nil - } - var ( - array []string = nil - ) - switch value := any.(type) { - case []int: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int8: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int16: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - return array - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []string{} - } - return []string{value} - case []uint16: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []bool: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []float32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []float64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []interface{}: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []string: - array = value - case [][]byte: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IStrings); ok { - return v.Strings() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Strings(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]string, length) - ) - for i := 0; i < length; i++ { - slice[i] = String(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []string{} - } - return []string{String(any)} - } + result, _ := defaultConverter.SliceStr(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 00ae9e491..a3c9f44c4 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -6,18 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceUint is alias of Uints. func SliceUint(any interface{}) []uint { return Uints(any) @@ -35,426 +23,18 @@ func SliceUint64(any interface{}) []uint64 { // Uints converts `any` to []uint. func Uints(any interface{}) []uint { - if empty.IsNil(any) { - return nil - } - var ( - array []uint = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []int8: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int16: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint: - array = value - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint{} - } - if utils.IsNumeric(value) { - return []uint{Uint(value)} - } - case []uint16: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []bool: - array = make([]uint, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []float64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []interface{}: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case [][]byte: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - } - - if array != nil { - return array - } - - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return v.Uints() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uints(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint{} - } - return []uint{Uint(any)} - } + result, _ := defaultConverter.SliceUint(any, SliceOption{}) + return result } // Uint32s converts `any` to []uint32. func Uint32s(any interface{}) []uint32 { - if empty.IsNil(any) { - return nil - } - var ( - array []uint32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []int8: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int16: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int32: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint32{} - } - if utils.IsNumeric(value) { - return []uint32{Uint32(value)} - } - case []uint16: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint32: - array = value - case []uint64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []bool: - array = make([]uint32, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []float64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []interface{}: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case [][]byte: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - } - if array != nil { - return array - } - - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return Uint32s(v.Uints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uint32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint32{} - } - return []uint32{Uint32(any)} - } + result, _ := defaultConverter.SliceUint32(any, SliceOption{}) + return result } // Uint64s converts `any` to []uint64. func Uint64s(any interface{}) []uint64 { - if empty.IsNil(any) { - return nil - } - var ( - array []uint64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []int8: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int16: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int64: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint64{} - } - if utils.IsNumeric(value) { - return []uint64{Uint64(value)} - } - case []uint16: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint64: - array = value - case []bool: - array = make([]uint64, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []float64: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []interface{}: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case [][]byte: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - } - if array != nil { - return array - } - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return Uint64s(v.Uints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uint64s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint64{} - } - return []uint64{Uint64(any)} - } + result, _ := defaultConverter.SliceUint64(any, SliceOption{}) + return result } diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index ace2236da..4f753132b 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -14,10 +14,8 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -type AnyConvertFunc func(from any, to reflect.Value) error - -// ConvertConfig is the configuration for type converting. -type ConvertConfig struct { +// Converter is the configuration for type converting. +type Converter struct { // map[reflect.Type]*CachedStructInfo cachedStructsInfoMap sync.Map @@ -28,9 +26,12 @@ type ConvertConfig struct { anyToTypeConvertMap map[reflect.Type]AnyConvertFunc } -// NewConvertConfig creates and returns a new ConvertConfig object. -func NewConvertConfig() *ConvertConfig { - return &ConvertConfig{ +// AnyConvertFunc is the function type for converting any to specified type. +type AnyConvertFunc func(from any, to reflect.Value) error + +// NewConverter creates and returns a new Converter object. +func NewConverter() *Converter { + return &Converter{ cachedStructsInfoMap: sync.Map{}, typeConverterFuncMap: make(map[reflect.Type]struct{}), anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), @@ -38,7 +39,7 @@ func NewConvertConfig() *ConvertConfig { } // RegisterTypeConvertFunc registers converting function for custom type. -func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) { +func (cf *Converter) RegisterTypeConvertFunc(fieldType reflect.Type) { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } @@ -46,7 +47,7 @@ func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) { } // RegisterAnyConvertFunc registers custom type converting function for specified type. -func (cf *ConvertConfig) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { +func (cf *Converter) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { cf.anyToTypeConvertMap[t] = convertFunc } diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index 98611ae16..44f1412df 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -15,7 +15,7 @@ import ( // GetCachedStructInfo retrieves or parses and returns a cached info for certain struct type. // The given `structType` should be type of struct. -func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { +func (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { if structType.Kind() != reflect.Struct { return nil } @@ -44,12 +44,12 @@ func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTa return cachedStructInfo } -func (cf *ConvertConfig) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { +func (cf *Converter) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { // Temporarily enabled as an experimental feature cf.cachedStructsInfoMap.Store(structType, cachedStructInfo) } -func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { +func (cf *Converter) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { // Temporarily enabled as an experimental feature v, ok := cf.cachedStructsInfoMap.Load(structType) if ok { @@ -60,7 +60,7 @@ func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*C // parseStructToCachedStructInfo parses given struct reflection type and stores its fields info into given CachedStructInfo. // It stores nothing into CachedStructInfo if given struct reflection type has no fields. -func (cf *ConvertConfig) parseStructToCachedStructInfo( +func (cf *Converter) parseStructToCachedStructInfo( structType reflect.Type, fieldIndexes []int, cachedStructInfo *CachedStructInfo,