github.com/gogf/gf/v2@v2.7.4/util/gconv/gconv.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  // Package gconv implements powerful and convenient converting functionality for any types of variables.
     8  //
     9  // This package should keep much fewer dependencies with other packages.
    10  package gconv
    11  
    12  import (
    13  	"context"
    14  	"fmt"
    15  	"math"
    16  	"reflect"
    17  	"strconv"
    18  	"strings"
    19  	"time"
    20  
    21  	"github.com/gogf/gf/v2/encoding/gbinary"
    22  	"github.com/gogf/gf/v2/internal/intlog"
    23  	"github.com/gogf/gf/v2/internal/json"
    24  	"github.com/gogf/gf/v2/internal/reflection"
    25  	"github.com/gogf/gf/v2/os/gtime"
    26  	"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
    27  	"github.com/gogf/gf/v2/util/gconv/internal/structcache"
    28  )
    29  
    30  var (
    31  	// Empty strings.
    32  	emptyStringMap = map[string]struct{}{
    33  		"":      {},
    34  		"0":     {},
    35  		"no":    {},
    36  		"off":   {},
    37  		"false": {},
    38  	}
    39  )
    40  
    41  // IUnmarshalValue is the interface for custom defined types customizing value assignment.
    42  // Note that only pointer can implement interface IUnmarshalValue.
    43  type IUnmarshalValue = localinterface.IUnmarshalValue
    44  
    45  func init() {
    46  	// register common converters for internal usage.
    47  	structcache.RegisterCommonConverter(structcache.CommonConverter{
    48  		Int64:   Int64,
    49  		Uint64:  Uint64,
    50  		String:  String,
    51  		Float32: Float32,
    52  		Float64: Float64,
    53  		Time:    Time,
    54  		GTime:   GTime,
    55  		Bytes:   Bytes,
    56  		Bool:    Bool,
    57  	})
    58  }
    59  
    60  // Byte converts `any` to byte.
    61  func Byte(any interface{}) byte {
    62  	if v, ok := any.(byte); ok {
    63  		return v
    64  	}
    65  	return Uint8(any)
    66  }
    67  
    68  // Bytes converts `any` to []byte.
    69  func Bytes(any interface{}) []byte {
    70  	if any == nil {
    71  		return nil
    72  	}
    73  	switch value := any.(type) {
    74  	case string:
    75  		return []byte(value)
    76  
    77  	case []byte:
    78  		return value
    79  
    80  	default:
    81  		if f, ok := value.(localinterface.IBytes); ok {
    82  			return f.Bytes()
    83  		}
    84  		originValueAndKind := reflection.OriginValueAndKind(any)
    85  		switch originValueAndKind.OriginKind {
    86  		case reflect.Map:
    87  			bytes, err := json.Marshal(any)
    88  			if err != nil {
    89  				intlog.Errorf(context.TODO(), `%+v`, err)
    90  			}
    91  			return bytes
    92  
    93  		case reflect.Array, reflect.Slice:
    94  			var (
    95  				ok    = true
    96  				bytes = make([]byte, originValueAndKind.OriginValue.Len())
    97  			)
    98  			for i := range bytes {
    99  				int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface())
   100  				if int32Value < 0 || int32Value > math.MaxUint8 {
   101  					ok = false
   102  					break
   103  				}
   104  				bytes[i] = byte(int32Value)
   105  			}
   106  			if ok {
   107  				return bytes
   108  			}
   109  		}
   110  		return gbinary.Encode(any)
   111  	}
   112  }
   113  
   114  // Rune converts `any` to rune.
   115  func Rune(any interface{}) rune {
   116  	if v, ok := any.(rune); ok {
   117  		return v
   118  	}
   119  	return Int32(any)
   120  }
   121  
   122  // Runes converts `any` to []rune.
   123  func Runes(any interface{}) []rune {
   124  	if v, ok := any.([]rune); ok {
   125  		return v
   126  	}
   127  	return []rune(String(any))
   128  }
   129  
   130  // String converts `any` to string.
   131  // It's most commonly used converting function.
   132  func String(any interface{}) string {
   133  	if any == nil {
   134  		return ""
   135  	}
   136  	switch value := any.(type) {
   137  	case int:
   138  		return strconv.Itoa(value)
   139  	case int8:
   140  		return strconv.Itoa(int(value))
   141  	case int16:
   142  		return strconv.Itoa(int(value))
   143  	case int32:
   144  		return strconv.Itoa(int(value))
   145  	case int64:
   146  		return strconv.FormatInt(value, 10)
   147  	case uint:
   148  		return strconv.FormatUint(uint64(value), 10)
   149  	case uint8:
   150  		return strconv.FormatUint(uint64(value), 10)
   151  	case uint16:
   152  		return strconv.FormatUint(uint64(value), 10)
   153  	case uint32:
   154  		return strconv.FormatUint(uint64(value), 10)
   155  	case uint64:
   156  		return strconv.FormatUint(value, 10)
   157  	case float32:
   158  		return strconv.FormatFloat(float64(value), 'f', -1, 32)
   159  	case float64:
   160  		return strconv.FormatFloat(value, 'f', -1, 64)
   161  	case bool:
   162  		return strconv.FormatBool(value)
   163  	case string:
   164  		return value
   165  	case []byte:
   166  		return string(value)
   167  	case time.Time:
   168  		if value.IsZero() {
   169  			return ""
   170  		}
   171  		return value.String()
   172  	case *time.Time:
   173  		if value == nil {
   174  			return ""
   175  		}
   176  		return value.String()
   177  	case gtime.Time:
   178  		if value.IsZero() {
   179  			return ""
   180  		}
   181  		return value.String()
   182  	case *gtime.Time:
   183  		if value == nil {
   184  			return ""
   185  		}
   186  		return value.String()
   187  	default:
   188  		if f, ok := value.(localinterface.IString); ok {
   189  			// If the variable implements the String() interface,
   190  			// then use that interface to perform the conversion
   191  			return f.String()
   192  		}
   193  		if f, ok := value.(localinterface.IError); ok {
   194  			// If the variable implements the Error() interface,
   195  			// then use that interface to perform the conversion
   196  			return f.Error()
   197  		}
   198  		// Reflect checks.
   199  		var (
   200  			rv   = reflect.ValueOf(value)
   201  			kind = rv.Kind()
   202  		)
   203  		switch kind {
   204  		case
   205  			reflect.Chan,
   206  			reflect.Map,
   207  			reflect.Slice,
   208  			reflect.Func,
   209  			reflect.Interface,
   210  			reflect.UnsafePointer:
   211  			if rv.IsNil() {
   212  				return ""
   213  			}
   214  		case reflect.String:
   215  			return rv.String()
   216  		case reflect.Ptr:
   217  			if rv.IsNil() {
   218  				return ""
   219  			}
   220  			return String(rv.Elem().Interface())
   221  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   222  			return strconv.FormatInt(rv.Int(), 10)
   223  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   224  			return strconv.FormatUint(rv.Uint(), 10)
   225  		case reflect.Uintptr:
   226  			return strconv.FormatUint(rv.Uint(), 10)
   227  		case reflect.Float32, reflect.Float64:
   228  			return strconv.FormatFloat(rv.Float(), 'f', -1, 64)
   229  		case reflect.Bool:
   230  			return strconv.FormatBool(rv.Bool())
   231  		}
   232  		// Finally, we use json.Marshal to convert.
   233  		if jsonContent, err := json.Marshal(value); err != nil {
   234  			return fmt.Sprint(value)
   235  		} else {
   236  			return string(jsonContent)
   237  		}
   238  	}
   239  }
   240  
   241  // Bool converts `any` to bool.
   242  // It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
   243  func Bool(any interface{}) bool {
   244  	if any == nil {
   245  		return false
   246  	}
   247  	switch value := any.(type) {
   248  	case bool:
   249  		return value
   250  	case []byte:
   251  		if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
   252  			return false
   253  		}
   254  		return true
   255  	case string:
   256  		if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
   257  			return false
   258  		}
   259  		return true
   260  	default:
   261  		if f, ok := value.(localinterface.IBool); ok {
   262  			return f.Bool()
   263  		}
   264  		rv := reflect.ValueOf(any)
   265  		switch rv.Kind() {
   266  		case reflect.Ptr:
   267  			if rv.IsNil() {
   268  				return false
   269  			}
   270  			if rv.Type().Elem().Kind() == reflect.Bool {
   271  				return rv.Elem().Bool()
   272  			}
   273  			return Bool(rv.Elem().Interface())
   274  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   275  			return rv.Int() != 0
   276  		case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   277  			return rv.Uint() != 0
   278  		case reflect.Float32, reflect.Float64:
   279  			return rv.Float() != 0
   280  		case reflect.Bool:
   281  			return rv.Bool()
   282  		// TODO:(Map,Array,Slice,Struct) It might panic here for these types.
   283  		case reflect.Map, reflect.Array:
   284  			fallthrough
   285  		case reflect.Slice:
   286  			return rv.Len() != 0
   287  		case reflect.Struct:
   288  			return true
   289  		default:
   290  			s := strings.ToLower(String(any))
   291  			if _, ok := emptyStringMap[s]; ok {
   292  				return false
   293  			}
   294  			return true
   295  		}
   296  	}
   297  }
   298  
   299  // checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`.
   300  func checkJsonAndUnmarshalUseNumber(any interface{}, target interface{}) bool {
   301  	switch r := any.(type) {
   302  	case []byte:
   303  		if json.Valid(r) {
   304  			if err := json.UnmarshalUseNumber(r, &target); err != nil {
   305  				return false
   306  			}
   307  			return true
   308  		}
   309  
   310  	case string:
   311  		anyAsBytes := []byte(r)
   312  		if json.Valid(anyAsBytes) {
   313  			if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil {
   314  				return false
   315  			}
   316  			return true
   317  		}
   318  	}
   319  	return false
   320  }