github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/convert.go (about)

     1  package f
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"reflect"
     8  	"strconv"
     9  	"unsafe"
    10  )
    11  
    12  // String converts byte slice to a string without memory allocation.
    13  // See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ
    14  func String(b []byte) string {
    15  	return *(*string)(unsafe.Pointer(&b))
    16  }
    17  
    18  // ToString convert number to string.
    19  func ToString(val interface{}) (str string) {
    20  	switch tVal := val.(type) {
    21  	case int:
    22  		str = strconv.FormatInt(int64(tVal), 10)
    23  	case int8:
    24  		str = strconv.FormatInt(int64(tVal), 10)
    25  	case int16:
    26  		str = strconv.FormatInt(int64(tVal), 10)
    27  	case int32:
    28  		str = strconv.FormatInt(int64(tVal), 10)
    29  	case int64:
    30  		str = strconv.FormatInt(tVal, 10)
    31  	case uint:
    32  		str = strconv.FormatUint(uint64(tVal), 10)
    33  	case uint8:
    34  		str = strconv.FormatUint(uint64(tVal), 10)
    35  	case uint16:
    36  		str = strconv.FormatUint(uint64(tVal), 10)
    37  	case uint32:
    38  		str = strconv.FormatUint(uint64(tVal), 10)
    39  	case uint64:
    40  		str = strconv.FormatUint(tVal, 10)
    41  	case float32, float64:
    42  		str = fmt.Sprintf("%g", tVal)
    43  	case string:
    44  		str = tVal
    45  	case []byte:
    46  		str = String(tVal)
    47  	case nil:
    48  		str = ""
    49  	default:
    50  		if t, ok := tVal.(fmt.Stringer); ok {
    51  			str = t.String()
    52  		} else if t, ok := tVal.(io.Reader); ok {
    53  			buf := new(bytes.Buffer)
    54  			if n, _ := buf.ReadFrom(t); n > 0 {
    55  				return buf.String()
    56  			}
    57  		} else {
    58  			str = fmt.Sprintf("%v", tVal)
    59  		}
    60  	}
    61  	return
    62  }
    63  
    64  // ToJSON convert the input to a valid JSON string.
    65  func ToJSON(obj interface{}) (string, error) {
    66  	res, err := EncodeJson(obj)
    67  	if err != nil {
    68  		res = []byte("")
    69  	}
    70  	return string(res), err
    71  }
    72  
    73  // Map check and convert the Map or Ptr to a map[string]interface{}.
    74  func Map(obj interface{}) (map[string]interface{}, bool) {
    75  	if obj == nil {
    76  		return nil, false
    77  	}
    78  
    79  	var (
    80  		rv reflect.Value
    81  		ok bool
    82  	)
    83  
    84  	if rv, ok = obj.(reflect.Value); !ok {
    85  		rv = reflect.ValueOf(obj)
    86  	}
    87  
    88  	if rv.Kind() == reflect.Ptr {
    89  		rv = rv.Elem()
    90  	}
    91  
    92  	if rv.Kind() == reflect.Map {
    93  		m := map[string]interface{}{}
    94  		for _, k := range rv.MapKeys() {
    95  			m[k.String()] = rv.MapIndex(k).Interface()
    96  		}
    97  		return m, true
    98  	}
    99  	return nil, false
   100  }
   101  
   102  // MapMerge recursively merges the src and dst maps. Key conflicts are resolved by
   103  // preferring src, or recursively descending, if both src and dst are maps.
   104  func MapMerge(dst, src map[string]interface{}) map[string]interface{} {
   105  	for key, srcVal := range src {
   106  		if dstVal, ok := dst[key]; ok {
   107  			srcMap, srcMapOk := Map(srcVal)
   108  			dstMap, dstMapOk := Map(dstVal)
   109  			if srcMapOk && dstMapOk {
   110  				srcVal = MapMerge(dstMap, srcMap)
   111  			}
   112  		}
   113  		dst[key] = srcVal
   114  	}
   115  	return dst
   116  }
   117  
   118  // ToMap convert the struct to a map[string]interface{}.
   119  func ToMap(obj interface{}) (map[string]interface{}, error) {
   120  	out := map[string]interface{}{}
   121  	v := reflect.ValueOf(obj)
   122  	if v.Kind() == reflect.Ptr {
   123  		v = v.Elem()
   124  	}
   125  	if v.Kind() != reflect.Struct {
   126  		return nil, fmt.Errorf("f.ToMap(obj) accepts only structs; got %T", v)
   127  	}
   128  	t := v.Type()
   129  	for i := 0; i < v.NumField(); i++ {
   130  		f := t.Field(i)
   131  		if v.Field(i).Kind() == reflect.Struct {
   132  			innerOut, err := ToMap(v.Field(i).Interface())
   133  			if err != nil {
   134  				return nil, err
   135  			}
   136  			out[f.Name] = innerOut
   137  		} else {
   138  			out[f.Name] = v.Field(i).Interface()
   139  		}
   140  	}
   141  	return out, nil
   142  }
   143  
   144  // ToMapOfTag convert the struct to a map[string]interface{} and a map with the tag's value.
   145  func ToMapOfTag(obj interface{}, tag string) (map[string]interface{}, map[string]interface{}, error) {
   146  	out := map[string]interface{}{}
   147  	tags := map[string]interface{}{}
   148  
   149  	v := reflect.ValueOf(obj)
   150  	if v.Kind() == reflect.Ptr {
   151  		v = v.Elem()
   152  	}
   153  	if v.Kind() != reflect.Struct {
   154  		return nil, nil, fmt.Errorf("f.ToMapOfTag(obj,tag) accepts only structs; got %T", v)
   155  	}
   156  	t := v.Type()
   157  	for i := 0; i < v.NumField(); i++ {
   158  		f := t.Field(i)
   159  		if v.Field(i).Kind() == reflect.Struct {
   160  			innerOut, innerTags, err := ToMapOfTag(v.Field(i).Interface(), tag)
   161  			if err != nil {
   162  				return nil, nil, err
   163  			}
   164  			out[f.Name] = innerOut
   165  			tags[f.Name] = innerTags
   166  		} else {
   167  			out[f.Name] = v.Field(i).Interface()
   168  			tags[f.Name] = f.Tag.Get(tag)
   169  		}
   170  	}
   171  	return out, tags, nil
   172  }
   173  
   174  // ToFloat convert the input string to a float, or 0.0 if the input is not a float.
   175  func ToFloat(str string) (float64, error) {
   176  	res, err := strconv.ParseFloat(str, 64)
   177  	if err != nil {
   178  		res = 0.0
   179  	}
   180  	return res, err
   181  }
   182  
   183  // Bytes converts string to a byte slice without memory allocation.
   184  // NOTE: panic if modify the member value of the []byte.
   185  func Bytes(s string) []byte {
   186  	//return *(*[]byte)(unsafe.Pointer(&s))
   187  	return *(*[]byte)(unsafe.Pointer(
   188  		&struct {
   189  			string
   190  			Cap int
   191  		}{s, len(s)},
   192  	))
   193  }
   194  
   195  // ToBytes converts string to a byte slice without memory allocation.
   196  // NOTE: panic if modify the member value of the []byte.
   197  func ToBytes(s string) []byte {
   198  	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
   199  	bh := reflect.SliceHeader{Data: sh.Data, Len: sh.Len, Cap: sh.Len}
   200  	return *(*[]byte)(unsafe.Pointer(&bh))
   201  }
   202  
   203  // BytesRepeat returns a new byte slice consisting of count copies of b.
   204  func BytesRepeat(b byte, count int) []byte {
   205  	nb := make([]byte, count)
   206  	for i := 0; i < count; i++ {
   207  		nb[i] = b
   208  	}
   209  	return nb
   210  }
   211  
   212  // BytesFromPtr converts a pointer to a byte slice without memory allocation.
   213  func BytesFromPtr(p uintptr, b []byte, off int64, size int32) int {
   214  	bh := reflect.SliceHeader{Data: p, Len: int(size), Cap: int(size)}
   215  	bb := *(*[]byte)(unsafe.Pointer(&bh))
   216  	return copy(b, bb[off:size])
   217  }
   218  
   219  // BytesToPtr converts a byte slice to a pointer without memory allocation.
   220  func BytesToPtr(b []byte, p uintptr, off int64, size int32) int {
   221  	bh := reflect.SliceHeader{Data: p, Len: int(size), Cap: int(size)}
   222  	bb := *(*[]byte)(unsafe.Pointer(&bh))
   223  	return copy(bb[off:], b)
   224  }
   225  
   226  // StringsConvert converts the string slice to a new slice using fn.
   227  // If fn returns error, exit the conversion and return the error.
   228  func StringsConvert(a []string, fn func(string) (string, error)) ([]string, error) {
   229  	ret := make([]string, len(a))
   230  	for i, s := range a {
   231  		r, err := fn(s)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		ret[i] = r
   236  	}
   237  	return ret, nil
   238  }
   239  
   240  // StringsConvertMap converts the string slice to a new map using fn.
   241  // If fn returns error, exit the conversion and return the error.
   242  func StringsConvertMap(a []string, fn func(string) (string, error)) (map[string]string, error) {
   243  	ret := make(map[string]string, len(a))
   244  	for _, s := range a {
   245  		r, err := fn(s)
   246  		if err != nil {
   247  			return nil, err
   248  		}
   249  		ret[s] = r
   250  	}
   251  	return ret, nil
   252  }
   253  
   254  // StringInSlice finds needle in a slice of strings.
   255  func StringInSlice(sliceString []string, needle string) bool {
   256  	for _, b := range sliceString {
   257  		if b == needle {
   258  			return true
   259  		}
   260  	}
   261  	return false
   262  }