github.com/wfusion/gofusion@v1.1.14/common/utils/conv.go (about)

     1  package utils
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/spf13/cast"
     9  
    10  	"github.com/wfusion/gofusion/common/constant"
    11  	"github.com/wfusion/gofusion/common/constraint"
    12  )
    13  
    14  // SliceMapping Mapping slice convert go1.18 version
    15  func SliceMapping[T, K any](s []T, mapFn func(t T) K) (d []K) {
    16  	if s == nil {
    17  		return
    18  	}
    19  	d = make([]K, 0, len(s))
    20  	for _, item := range s {
    21  		d = append(d, mapFn(item))
    22  	}
    23  	return
    24  }
    25  
    26  // SortableToGeneric convert sortable type to generic type
    27  func SortableToGeneric[T, K constraint.Sortable](s T) (d K) {
    28  	switch any(d).(type) {
    29  	case int:
    30  		return any(cast.ToInt(s)).(K)
    31  	case int8:
    32  		return any(cast.ToInt8(s)).(K)
    33  	case int16:
    34  		return any(cast.ToInt16(s)).(K)
    35  	case int32:
    36  		return any(cast.ToInt32(s)).(K)
    37  	case int64:
    38  		return any(cast.ToInt64(s)).(K)
    39  	case *int:
    40  		return any(AnyPtr(cast.ToInt(s))).(K)
    41  	case *int8:
    42  		return any(AnyPtr(cast.ToInt8(s))).(K)
    43  	case *int16:
    44  		return any(AnyPtr(cast.ToInt16(s))).(K)
    45  	case *int32:
    46  		return any(AnyPtr(cast.ToInt32(s))).(K)
    47  	case *int64:
    48  		return any(AnyPtr(cast.ToInt64(s))).(K)
    49  	case uint:
    50  		return any(cast.ToUint(s)).(K)
    51  	case uint8:
    52  		return any(cast.ToUint8(s)).(K)
    53  	case uint16:
    54  		return any(cast.ToUint16(s)).(K)
    55  	case uint32:
    56  		return any(cast.ToUint32(s)).(K)
    57  	case uint64:
    58  		return any(cast.ToUint64(s)).(K)
    59  	case *uint:
    60  		return any(AnyPtr(cast.ToUint(s))).(K)
    61  	case *uint8:
    62  		return any(AnyPtr(cast.ToUint8(s))).(K)
    63  	case *uint16:
    64  		return any(AnyPtr(cast.ToUint16(s))).(K)
    65  	case *uint32:
    66  		return any(AnyPtr(cast.ToUint32(s))).(K)
    67  	case *uint64:
    68  		return any(AnyPtr(cast.ToUint64(s))).(K)
    69  	case float32:
    70  		return any(cast.ToFloat32(s)).(K)
    71  	case float64:
    72  		return any(cast.ToFloat64(s)).(K)
    73  	case *float32:
    74  		return any(AnyPtr(cast.ToFloat32(s))).(K)
    75  	case *float64:
    76  		return any(AnyPtr(cast.ToFloat64(s))).(K)
    77  	case string:
    78  		return any(cast.ToString(s)).(K)
    79  	case *string:
    80  		return any(AnyPtr(cast.ToString(s))).(K)
    81  	default:
    82  		panic(errors.Errorf("cannot mapping %T", d))
    83  	}
    84  }
    85  
    86  var sortableReflectType = []reflect.Type{
    87  	constant.IntType,
    88  	constant.UintType,
    89  	constant.StringType,
    90  	constant.Float32Type,
    91  	constant.Float64Type,
    92  	constant.BoolType,
    93  }
    94  
    95  // ComparableToSortable convert generic type to sortable type
    96  func ComparableToSortable[T comparable](s T) (d any) {
    97  	val := reflect.ValueOf(s)
    98  	typ := val.Type()
    99  	for _, sortableType := range sortableReflectType {
   100  		if typ.ConvertibleTo(sortableType) {
   101  			return val.Convert(sortableType).Interface()
   102  		}
   103  	}
   104  
   105  	return
   106  }
   107  
   108  // SliceConvert >= go1.18 recommend to use SliceMapping
   109  func SliceConvert(src any, dstType reflect.Type) any {
   110  	srcVal := reflect.ValueOf(src)
   111  	srcType := reflect.TypeOf(src)
   112  	dstVal := reflect.Indirect(reflect.New(dstType))
   113  	if srcType.Kind() != reflect.Slice || dstType.Kind() != reflect.Slice {
   114  		panic(errors.Errorf("src or dst type is invalid [src[%s] dst[%s]]", srcType.Kind(), dstType.Kind()))
   115  	}
   116  
   117  	isInterfaceSlice := false
   118  	srcElemType := srcType.Elem()
   119  	if srcType == constant.AnySliceType {
   120  		if srcVal.Len() == 0 {
   121  			return dstVal.Interface()
   122  		}
   123  		srcElemType = reflect.TypeOf(srcVal.Index(0).Interface())
   124  		isInterfaceSlice = true
   125  	}
   126  
   127  	dstElemType := dstType.Elem()
   128  	if !srcElemType.ConvertibleTo(dstElemType) {
   129  		panic(errors.Errorf("src elem is not convertible to dst elem [src[%s] dst[%s]]",
   130  			srcElemType.Kind(), dstElemType.Kind()))
   131  	}
   132  
   133  	length := srcVal.Len()
   134  	for i := 0; i < length; i++ {
   135  		srcElem := srcVal.Index(i)
   136  		if isInterfaceSlice {
   137  			srcElem = reflect.ValueOf(srcVal.Index(i).Interface())
   138  		}
   139  		dstVal = reflect.Append(dstVal, srcElem.Convert(dstElemType))
   140  	}
   141  
   142  	return dstVal.Interface()
   143  }
   144  
   145  func AnyPtr[T any](s T) *T { return &s }
   146  
   147  // UnsafeStringToBytes converts string to byte slice without a memory allocation.
   148  // Fork from github.com/gin-gonic/gin@v1.7.7/internal/bytesconv/bytesconv.go
   149  func UnsafeStringToBytes(s string) []byte {
   150  	return *(*[]byte)(unsafe.Pointer(
   151  		&struct {
   152  			string
   153  			Cap int
   154  		}{s, len(s)},
   155  	))
   156  }
   157  
   158  // UnsafeBytesToString converts byte slice to string without a memory allocation.
   159  // Fork from github.com/gin-gonic/gin@v1.7.7/internal/bytesconv/bytesconv.go
   160  func UnsafeBytesToString(b []byte) string {
   161  	return *(*string)(unsafe.Pointer(&b))
   162  }