161 lines
3.3 KiB
Go
161 lines
3.3 KiB
Go
package goref
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
func ToString(val any) (string, bool) {
|
|
vo := reflect.ValueOf(val)
|
|
if vo.Kind() == reflect.Ptr {
|
|
vo = vo.Elem()
|
|
}
|
|
if vo.Kind() == reflect.String {
|
|
return vo.String(), true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
func ToStrings(val any) ([]string, bool) {
|
|
vo := reflect.ValueOf(val)
|
|
if vo.Kind() == reflect.Ptr {
|
|
vo = vo.Elem()
|
|
}
|
|
if vo.Kind() == reflect.Slice || vo.Kind() == reflect.Array {
|
|
var list []string
|
|
for i := 0; i < vo.Len(); i++ {
|
|
val := vo.Index(i).Interface()
|
|
valVo := reflect.ValueOf(val)
|
|
if valVo.Kind() == reflect.Ptr {
|
|
valVo = valVo.Elem()
|
|
}
|
|
if valVo.Kind() == reflect.String {
|
|
list = append(list, valVo.String())
|
|
}
|
|
}
|
|
return list, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func ToInterfaces(val any) ([]interface{}, bool) {
|
|
vo := reflect.ValueOf(val)
|
|
if vo.Kind() == reflect.Ptr {
|
|
vo = vo.Elem()
|
|
}
|
|
if vo.Len() == 0 {
|
|
return nil, false
|
|
}
|
|
var result []interface{}
|
|
for i := 0; i < vo.Len(); i++ {
|
|
result = append(result, vo.Index(i).Interface())
|
|
}
|
|
return result, true
|
|
}
|
|
|
|
type tagger struct {
|
|
tag string
|
|
omitempty bool
|
|
}
|
|
|
|
func (t *tagger) merge() {
|
|
if t.tag == "" {
|
|
t.tag = "-"
|
|
}
|
|
}
|
|
|
|
type taggerOption func(*tagger)
|
|
|
|
func WithTag(tag string) taggerOption {
|
|
return func(tager *tagger) {
|
|
tager.tag = tag
|
|
}
|
|
}
|
|
|
|
func WithOmitempty(omit bool) taggerOption {
|
|
return func(tager *tagger) {
|
|
tager.omitempty = omit
|
|
}
|
|
}
|
|
|
|
func StructToMap(val any, tagOpts ...taggerOption) (map[string]interface{}, error) {
|
|
vo := reflect.ValueOf(val)
|
|
if vo.Kind() == reflect.Ptr {
|
|
vo = vo.Elem()
|
|
}
|
|
if vo.Kind() != reflect.Struct {
|
|
return nil, fmt.Errorf("val type not struct")
|
|
}
|
|
var data = make(map[string]interface{})
|
|
var tagger = new(tagger)
|
|
for _, opt := range tagOpts {
|
|
opt(tagger)
|
|
}
|
|
tagger.merge()
|
|
for i := 0; i < vo.NumField(); i++ {
|
|
vf := vo.Field(i)
|
|
if tagger.omitempty && vf.IsZero() {
|
|
continue
|
|
}
|
|
key := vo.Type().Field(i).Tag.Get(tagger.tag)
|
|
if key == "" {
|
|
key = vo.Type().Field(i).Name
|
|
}
|
|
if strings.Contains(key, ",omitempty") {
|
|
key = strings.Replace(key, ",omitempty", "", 1)
|
|
}
|
|
data[key] = vf.Interface()
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// SliceStructToMap slice struct to map, field as key
|
|
// value type []struct, bind type *map[string]*struct
|
|
func SliceStructToMap(value, bind any, field string) error {
|
|
// bind type check
|
|
if GetListBaseType(value) != GetMapValueBaseType(bind) {
|
|
return fmt.Errorf("struct type no match map type")
|
|
}
|
|
|
|
vo := reflect.ValueOf(value)
|
|
if vo.Kind() == reflect.Ptr {
|
|
vo = vo.Elem()
|
|
}
|
|
if vo.Kind() != reflect.Slice && vo.Kind() != reflect.Array {
|
|
return fmt.Errorf("val type not array or slice: " + vo.String())
|
|
}
|
|
|
|
bo := reflect.ValueOf(bind)
|
|
if bo.Kind() == reflect.Ptr {
|
|
bo = bo.Elem()
|
|
}
|
|
if bo.Kind() != reflect.Map {
|
|
return fmt.Errorf("invalid map type")
|
|
}
|
|
if !bo.CanSet() {
|
|
return fmt.Errorf("bind map must be initialized")
|
|
}
|
|
boKey := bo.Type().Key()
|
|
boVal := bo.Type().Elem()
|
|
bo.Set(reflect.MakeMap(reflect.MapOf(boKey, boVal)))
|
|
|
|
for i := 0; i < vo.Len(); i++ {
|
|
t := vo.Index(i)
|
|
if t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
idxField := t.FieldByName(field)
|
|
if idxField.Kind() == reflect.Invalid {
|
|
continue
|
|
}
|
|
idxVal := vo.Index(i)
|
|
if boVal.Kind() == reflect.Ptr {
|
|
bo.SetMapIndex(idxField, idxVal.Addr())
|
|
} else {
|
|
bo.SetMapIndex(idxField, idxVal)
|
|
}
|
|
}
|
|
return nil
|
|
}
|