You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
4.9 KiB
221 lines
4.9 KiB
package Any
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
"regexp"
|
|
"strconv"
|
|
)
|
|
|
|
// Bytes convert any to bytes
|
|
func Bytes(value any) ([]byte, error) {
|
|
v := reflect.ValueOf(value)
|
|
|
|
switch value.(type) {
|
|
case int, int8, int16, int32, int64:
|
|
number := v.Int()
|
|
buf := bytes.NewBuffer([]byte{})
|
|
buf.Reset()
|
|
err := binary.Write(buf, binary.BigEndian, number)
|
|
return buf.Bytes(), err
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
number := v.Uint()
|
|
buf := bytes.NewBuffer([]byte{})
|
|
buf.Reset()
|
|
err := binary.Write(buf, binary.BigEndian, number)
|
|
return buf.Bytes(), err
|
|
case float32:
|
|
number := float32(v.Float())
|
|
bits := math.Float32bits(number)
|
|
bytes := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bytes, bits)
|
|
return bytes, nil
|
|
case float64:
|
|
number := v.Float()
|
|
bits := math.Float64bits(number)
|
|
bytes := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(bytes, bits)
|
|
return bytes, nil
|
|
case bool:
|
|
return strconv.AppendBool([]byte{}, v.Bool()), nil
|
|
case string:
|
|
return []byte(v.String()), nil
|
|
case []byte:
|
|
return v.Bytes(), nil
|
|
default:
|
|
newValue, err := json.Marshal(value)
|
|
return newValue, err
|
|
}
|
|
}
|
|
|
|
// String convert value to string
|
|
func String(value any) string {
|
|
result := ""
|
|
if value == nil {
|
|
return result
|
|
}
|
|
|
|
v := reflect.ValueOf(value)
|
|
|
|
switch value.(type) {
|
|
case float32, float64:
|
|
result = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
|
return result
|
|
case int, int8, int16, int32, int64:
|
|
result = strconv.FormatInt(v.Int(), 10)
|
|
return result
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
result = strconv.FormatUint(v.Uint(), 10)
|
|
return result
|
|
case string:
|
|
result = v.String()
|
|
return result
|
|
case []byte:
|
|
result = string(v.Bytes())
|
|
return result
|
|
default:
|
|
newValue, _ := json.Marshal(value)
|
|
result = string(newValue)
|
|
return result
|
|
}
|
|
}
|
|
|
|
// Float convert value to a float64, if input is not a float return 0.0 and error
|
|
func Float(value any) (float64, error) {
|
|
v := reflect.ValueOf(value)
|
|
|
|
result := 0.0
|
|
err := fmt.Errorf("ToInt: unvalid interface type %T", value)
|
|
switch value.(type) {
|
|
case int, int8, int16, int32, int64:
|
|
result = float64(v.Int())
|
|
return result, nil
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
result = float64(v.Uint())
|
|
return result, nil
|
|
case float32, float64:
|
|
result = v.Float()
|
|
return result, nil
|
|
case string:
|
|
result, err = strconv.ParseFloat(v.String(), 64)
|
|
if err != nil {
|
|
result = 0.0
|
|
}
|
|
return result, err
|
|
default:
|
|
return result, err
|
|
}
|
|
}
|
|
|
|
// Int convert value to a int64, if input is not a numeric format return 0 and error
|
|
func Int(value any) (int64, error) {
|
|
v := reflect.ValueOf(value)
|
|
|
|
var result int64
|
|
err := fmt.Errorf("ToInt: invalid interface type %T", value)
|
|
switch value.(type) {
|
|
case int, int8, int16, int32, int64:
|
|
result = v.Int()
|
|
return result, nil
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
result = int64(v.Uint())
|
|
return result, nil
|
|
case float32, float64:
|
|
result = int64(v.Float())
|
|
return result, nil
|
|
case string:
|
|
result, err = strconv.ParseInt(v.String(), 0, 64)
|
|
if err != nil {
|
|
result = 0
|
|
}
|
|
return result, err
|
|
default:
|
|
return result, err
|
|
}
|
|
}
|
|
|
|
// Pointer returns a pointer to this value
|
|
func Pointer[T any](value T) *T {
|
|
return &value
|
|
}
|
|
|
|
// Map convert a slice or an array of structs to a map based on iteratee function
|
|
func Map[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
|
|
result := make(map[K]V, len(array))
|
|
for _, item := range array {
|
|
k, v := iteratee(item)
|
|
result[k] = v
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// StructToMap convert struct to map, only convert exported struct field
|
|
// map key is specified same as struct field tag `json` value
|
|
func StructToMap(value any) (map[string]any, error) {
|
|
v := reflect.ValueOf(value)
|
|
t := reflect.TypeOf(value)
|
|
|
|
if t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
if t.Kind() != reflect.Struct {
|
|
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", value)
|
|
}
|
|
|
|
result := make(map[string]any)
|
|
|
|
fieldNum := t.NumField()
|
|
pattern := `^[A-Z]`
|
|
regex := regexp.MustCompile(pattern)
|
|
for i := 0; i < fieldNum; i++ {
|
|
name := t.Field(i).Name
|
|
tag := t.Field(i).Tag.Get("json")
|
|
if regex.MatchString(name) && tag != "" {
|
|
//result[name] = v.Field(i).Interface()
|
|
result[tag] = v.Field(i).Interface()
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// MapToSlice convert a map to a slice based on iteratee function
|
|
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
|
|
result := make([]T, 0, len(aMap))
|
|
|
|
for k, v := range aMap {
|
|
result = append(result, iteratee(k, v))
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Json convert value to a valid json string
|
|
func Json(value any) (string, error) {
|
|
result, err := json.Marshal(value)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(result), nil
|
|
}
|
|
|
|
// Channel convert a array of elements to a read-only channels
|
|
func Channel[T any](array []T) <-chan T {
|
|
ch := make(chan T)
|
|
|
|
go func() {
|
|
for _, item := range array {
|
|
ch <- item
|
|
}
|
|
close(ch)
|
|
}()
|
|
|
|
return ch
|
|
}
|