788 lines
18 KiB
Go
788 lines
18 KiB
Go
package cast
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// If 泛型三元表达式
|
|
func If[T any](condition bool, trueVal, falseVal T) T {
|
|
if condition {
|
|
return trueVal
|
|
}
|
|
return falseVal
|
|
}
|
|
|
|
// In 泛型包含判断
|
|
func In[T comparable](arr []T, val T) bool {
|
|
return slices.Contains(arr, val)
|
|
}
|
|
|
|
func RealValue(v reflect.Value) reflect.Value {
|
|
for v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
|
|
if v.IsNil() {
|
|
return v
|
|
}
|
|
v = v.Elem()
|
|
}
|
|
return v
|
|
}
|
|
|
|
// --- Core Cast Logic ---
|
|
|
|
func parseInt(s string) int64 {
|
|
i, err := strconv.ParseInt(s, 10, 64)
|
|
if err == nil {
|
|
return i
|
|
}
|
|
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
|
return int64(f)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func parseUint(s string) uint64 {
|
|
i, err := strconv.ParseUint(s, 10, 64)
|
|
if err == nil {
|
|
return i
|
|
}
|
|
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
|
return uint64(f)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func Int(value any) int { return int(Int64(value)) }
|
|
|
|
// Helper for integer coercion to avoid repetition
|
|
func toInt64(value any) (int64, bool) {
|
|
switch v := value.(type) {
|
|
case int: return int64(v), true
|
|
case int8: return int64(v), true
|
|
case int16: return int64(v), true
|
|
case int32: return int64(v), true
|
|
case int64: return v, true
|
|
case uint: return int64(v), true
|
|
case uint8: return int64(v), true
|
|
case uint16: return int64(v), true
|
|
case uint32: return int64(v), true
|
|
case uint64: return int64(v), true
|
|
case float32: return int64(v), true
|
|
case float64: return int64(v), true
|
|
case bool: return If(v, int64(1), int64(0)), true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func Int64(value any) int64 {
|
|
if value == nil { return 0 }
|
|
if i, ok := toInt64(value); ok { return i }
|
|
|
|
switch realValue := value.(type) {
|
|
case []byte: return parseInt(string(realValue))
|
|
case string: return parseInt(realValue)
|
|
}
|
|
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Int64(rv.Interface())
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func Uint(value any) uint { return uint(Uint64(value)) }
|
|
|
|
func Uint64(value any) uint64 {
|
|
if value == nil {
|
|
return 0
|
|
}
|
|
switch realValue := value.(type) {
|
|
case int:
|
|
return uint64(realValue)
|
|
case int8:
|
|
return uint64(realValue)
|
|
case int16:
|
|
return uint64(realValue)
|
|
case int32:
|
|
return uint64(realValue)
|
|
case int64:
|
|
return uint64(realValue)
|
|
case uint:
|
|
return uint64(realValue)
|
|
case uint8:
|
|
return uint64(realValue)
|
|
case uint16:
|
|
return uint64(realValue)
|
|
case uint32:
|
|
return uint64(realValue)
|
|
case uint64:
|
|
return realValue
|
|
case float32:
|
|
return uint64(realValue)
|
|
case float64:
|
|
return uint64(realValue)
|
|
case bool:
|
|
return If(realValue, uint64(1), uint64(0))
|
|
case []byte:
|
|
return parseUint(string(realValue))
|
|
case string:
|
|
return parseUint(realValue)
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Uint64(rv.Interface())
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func Float(value any) float32 { return float32(Float64(value)) }
|
|
|
|
func Float64(value any) float64 {
|
|
if value == nil {
|
|
return 0
|
|
}
|
|
switch realValue := value.(type) {
|
|
case int, int8, int16, int32, int64:
|
|
return float64(Int64(realValue))
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
return float64(Uint64(realValue))
|
|
case float32:
|
|
return float64(realValue)
|
|
case float64:
|
|
return realValue
|
|
case bool:
|
|
return If(realValue, 1.0, 0.0)
|
|
case []byte:
|
|
i, err := strconv.ParseFloat(string(realValue), 64)
|
|
if err == nil {
|
|
return i
|
|
}
|
|
case string:
|
|
i, err := strconv.ParseFloat(realValue, 64)
|
|
if err == nil {
|
|
return i
|
|
}
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Float64(rv.Interface())
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func String(value any) string {
|
|
if value == nil {
|
|
return ""
|
|
}
|
|
switch realValue := value.(type) {
|
|
case int, int8, int16, int32, int64:
|
|
return strconv.FormatInt(Int64(realValue), 10)
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
return strconv.FormatUint(Uint64(realValue), 10)
|
|
case float32:
|
|
return strconv.FormatFloat(float64(realValue), 'f', -1, 32)
|
|
case float64:
|
|
return strconv.FormatFloat(realValue, 'f', -1, 64)
|
|
case bool:
|
|
return If(realValue, "true", "false")
|
|
case string:
|
|
return realValue
|
|
case []byte:
|
|
return string(realValue)
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return String(rv.Interface())
|
|
}
|
|
}
|
|
return fmt.Sprint(value)
|
|
}
|
|
|
|
func Bool(value any) bool {
|
|
switch realValue := value.(type) {
|
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
|
|
return Uint64(realValue) != 0
|
|
case bool:
|
|
return realValue
|
|
case []byte:
|
|
s := strings.ToLower(string(realValue))
|
|
return s == "1" || s == "t" || s == "true"
|
|
case string:
|
|
s := strings.ToLower(realValue)
|
|
return s == "1" || s == "t" || s == "true"
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Bool(rv.Interface())
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func Ints(value any) []int64 {
|
|
switch realValue := value.(type) {
|
|
case []any:
|
|
result := make([]int64, len(realValue))
|
|
for i, v := range realValue {
|
|
result[i] = Int64(v)
|
|
}
|
|
return result
|
|
case string:
|
|
if strings.HasPrefix(realValue, "[") {
|
|
result := make([]int64, 0)
|
|
UnmarshalJSON(realValue, &result)
|
|
return result
|
|
}
|
|
return []int64{Int64(value)}
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Ints(rv.Interface())
|
|
}
|
|
}
|
|
return []int64{Int64(value)}
|
|
}
|
|
|
|
func Strings(value any) []string {
|
|
switch realValue := value.(type) {
|
|
case []any:
|
|
result := make([]string, len(realValue))
|
|
for i, v := range realValue {
|
|
result[i] = String(v)
|
|
}
|
|
return result
|
|
case string:
|
|
if strings.HasPrefix(realValue, "[") {
|
|
result := make([]string, 0)
|
|
UnmarshalJSON(realValue, &result)
|
|
return result
|
|
}
|
|
return []string{String(value)}
|
|
}
|
|
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Strings(rv.Interface())
|
|
}
|
|
}
|
|
return []string{String(value)}
|
|
}
|
|
|
|
func Duration(value any) time.Duration {
|
|
if value == nil {
|
|
return 0
|
|
}
|
|
switch realValue := value.(type) {
|
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
|
return time.Duration(Int64(realValue))
|
|
case float32, float64:
|
|
return time.Duration(Float64(realValue) * float64(time.Second))
|
|
case []byte, string:
|
|
if result, err := time.ParseDuration(String(realValue)); err == nil {
|
|
return result
|
|
}
|
|
}
|
|
rv := reflect.ValueOf(value)
|
|
if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface {
|
|
if rv = RealValue(rv); rv.IsValid() && rv.CanInterface() && rv.Kind() != reflect.Pointer {
|
|
return Duration(rv.Interface())
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func ToJSONBytes(value any) ([]byte, error) {
|
|
buf := &bytes.Buffer{}
|
|
enc := json.NewEncoder(buf)
|
|
enc.SetEscapeHTML(false) // 现代改进:不再需要手动 FixJSONBytes
|
|
if err := enc.Encode(value); err != nil {
|
|
v2 := makeJSONType(reflect.ValueOf(value))
|
|
if v2 != nil {
|
|
buf.Reset()
|
|
err = enc.Encode(v2.Interface())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
bytesResult := bytes.TrimRight(buf.Bytes(), "\n")
|
|
excludeKeys := makeExcludeUpperKeys(value, "", 0)
|
|
if len(bytesResult) == 4 && string(bytesResult) == "null" {
|
|
t := reflect.TypeOf(bytesResult)
|
|
if t.Kind() == reflect.Slice {
|
|
bytesResult = []byte("[]")
|
|
}
|
|
if t.Kind() == reflect.Map {
|
|
bytesResult = []byte("{}")
|
|
}
|
|
}
|
|
FixUpperCase(bytesResult, excludeKeys)
|
|
return bytesResult, nil
|
|
}
|
|
|
|
func MustJSONBytes(value any) []byte {
|
|
j, err := ToJSONBytes(value)
|
|
if err != nil {
|
|
return []byte{}
|
|
}
|
|
return j
|
|
}
|
|
|
|
func ToJSON(value any) (string, error) {
|
|
j, err := ToJSONBytes(value)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(j), nil
|
|
}
|
|
func MustToJSON(value any) string { return string(MustJSONBytes(value)) }
|
|
|
|
func PrettyToJSONBytes(value any) []byte {
|
|
j := MustJSONBytes(value)
|
|
r := &bytes.Buffer{}
|
|
if err := json.Indent(r, j, "", " "); err == nil {
|
|
return r.Bytes()
|
|
}
|
|
return j
|
|
}
|
|
|
|
func PrettyToJSON(value any) string { return string(PrettyToJSONBytes(value)) }
|
|
|
|
func UnmarshalJSONBytes(data []byte, value any) (any, error) {
|
|
if value == nil {
|
|
var v any
|
|
value = &v
|
|
}
|
|
err := json.Unmarshal(data, value)
|
|
return value, err
|
|
}
|
|
|
|
func MustUnmarshalJSONBytes(data []byte, value any) any {
|
|
v, err := UnmarshalJSONBytes(data, value)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
func UnmarshalJSON(str string, value any) (any, error) { return UnmarshalJSONBytes([]byte(str), value) }
|
|
|
|
func MustUnmarshalJSON(str string, value any) any { return MustUnmarshalJSONBytes([]byte(str), value) }
|
|
|
|
func ToYAML(value any) (string, error) {
|
|
j, err := YAMLBytes(value)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(j), nil
|
|
}
|
|
|
|
func MustToYAML(value any) string { return string(MustYAMLBytes(value)) }
|
|
|
|
func UnmarshalYAML(data string, value any) (any, error) {
|
|
return UnmarshalYAMLBytes([]byte(data), value)
|
|
}
|
|
|
|
func MustUnmarshalYAML(data string, value any) any { return MustUnmarshalYAMLBytes([]byte(data), value) }
|
|
|
|
func YAMLBytes(value any) ([]byte, error) {
|
|
j, err := yaml.Marshal(value)
|
|
if err == nil {
|
|
return j, nil
|
|
}
|
|
return []byte(fmt.Sprint(value)), err
|
|
}
|
|
|
|
func MustYAMLBytes(value any) []byte {
|
|
j, err := YAMLBytes(value)
|
|
if err != nil {
|
|
return []byte{}
|
|
}
|
|
return j
|
|
}
|
|
|
|
func UnmarshalYAMLBytes(data []byte, value any) (any, error) {
|
|
err := yaml.Unmarshal(data, value)
|
|
return value, err
|
|
}
|
|
|
|
func MustUnmarshalYAMLBytes(data []byte, value any) any {
|
|
v, err := UnmarshalYAMLBytes(data, value)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
// --- Others (Keep logic but clean style) ---
|
|
|
|
func Split(s, sep string) []string {
|
|
ss := strings.Split(s, sep)
|
|
out := make([]string, 0, len(ss))
|
|
for _, s1 := range ss {
|
|
if s2 := strings.TrimSpace(s1); s2 != "" {
|
|
out = append(out, s2)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func SplitArgs(s string) []string {
|
|
var res []string
|
|
var builder strings.Builder
|
|
inQuote := false
|
|
escaped := false
|
|
|
|
chars := []rune(s)
|
|
for i := 0; i < len(chars); i++ {
|
|
c := chars[i]
|
|
|
|
if escaped {
|
|
builder.WriteRune(c)
|
|
escaped = false
|
|
continue
|
|
}
|
|
|
|
if c == '\\' {
|
|
escaped = true
|
|
continue
|
|
}
|
|
|
|
if c == '"' {
|
|
inQuote = !inQuote
|
|
continue
|
|
}
|
|
|
|
if c == ' ' && !inQuote {
|
|
if builder.Len() > 0 {
|
|
res = append(res, builder.String())
|
|
builder.Reset()
|
|
}
|
|
continue
|
|
}
|
|
|
|
builder.WriteRune(c)
|
|
}
|
|
|
|
if builder.Len() > 0 {
|
|
res = append(res, builder.String())
|
|
}
|
|
return res
|
|
}
|
|
|
|
func JoinArgs(arr []string, sep string) string {
|
|
var builder strings.Builder
|
|
for i, s := range arr {
|
|
if i > 0 {
|
|
builder.WriteString(sep)
|
|
}
|
|
// 如果包含空格或引号,则需要包裹引号并转义内部引号
|
|
if strings.ContainsRune(s, ' ') || strings.ContainsRune(s, '"') {
|
|
builder.WriteByte('"')
|
|
builder.WriteString(strings.ReplaceAll(s, "\"", "\\\""))
|
|
builder.WriteByte('"')
|
|
} else {
|
|
builder.WriteString(s)
|
|
}
|
|
}
|
|
return builder.String()
|
|
}
|
|
|
|
func UniqueAppend(to []string, from ...any) []string {
|
|
exists := make(map[string]struct{}, len(to))
|
|
for _, s := range to {
|
|
exists[s] = struct{}{}
|
|
}
|
|
for _, a := range from {
|
|
s := String(a)
|
|
if _, ok := exists[s]; !ok {
|
|
to = append(to, s)
|
|
exists[s] = struct{}{}
|
|
}
|
|
}
|
|
return to
|
|
}
|
|
|
|
func ArrayToBoolMap[T comparable](arr []T) map[T]bool {
|
|
r := map[T]bool{}
|
|
for _, s := range arr {
|
|
r[s] = true
|
|
}
|
|
return r
|
|
}
|
|
|
|
func makeJSONType(inValue reflect.Value) *reflect.Value {
|
|
if inValue.Kind() == reflect.Interface {
|
|
inValue = inValue.Elem()
|
|
}
|
|
for inValue.Kind() == reflect.Ptr {
|
|
inValue = inValue.Elem()
|
|
}
|
|
|
|
if !inValue.IsValid() {
|
|
return nil
|
|
}
|
|
|
|
inType := inValue.Type()
|
|
|
|
switch inType.Kind() {
|
|
case reflect.Map:
|
|
if inType.Key().Kind() == reflect.Interface {
|
|
// 测试是否为数组
|
|
isMap := false
|
|
length := inValue.Len()
|
|
|
|
// 数组必须从 0 开始且连续
|
|
for i := range length {
|
|
// 依次尝试 int, float64, string 三种可能的 Key 类型
|
|
if inValue.MapIndex(reflect.ValueOf(i)).Kind() == reflect.Invalid &&
|
|
inValue.MapIndex(reflect.ValueOf(float64(i))).Kind() == reflect.Invalid &&
|
|
inValue.MapIndex(reflect.ValueOf(strconv.Itoa(i))).Kind() == reflect.Invalid {
|
|
isMap = true
|
|
break
|
|
}
|
|
}
|
|
if isMap {
|
|
// 处理字典
|
|
newMap := reflect.MakeMap(reflect.MapOf(reflect.TypeFor[string](), inType.Elem()))
|
|
for _, k := range inValue.MapKeys() {
|
|
v1 := inValue.MapIndex(k)
|
|
v2 := makeJSONType(v1)
|
|
var k2 reflect.Value
|
|
if k.CanInterface() {
|
|
k2 = reflect.ValueOf(String(k.Interface()))
|
|
} else {
|
|
k2 = reflect.ValueOf(k.String())
|
|
}
|
|
|
|
if v2 != nil {
|
|
newMap.SetMapIndex(k2, *v2)
|
|
} else {
|
|
newMap.SetMapIndex(k2, v1)
|
|
}
|
|
}
|
|
return &newMap
|
|
} else {
|
|
// 处理数组:按数字 Key 填入对应的 Index
|
|
newArray := reflect.MakeSlice(reflect.SliceOf(inType.Elem()), length, length)
|
|
for _, k := range inValue.MapKeys() {
|
|
v1 := inValue.MapIndex(k)
|
|
v2 := makeJSONType(v1)
|
|
|
|
idx := int(Int64(k.Interface())) // 统一转为 int
|
|
if idx >= 0 && idx < length {
|
|
if v2 != nil {
|
|
newArray.Index(idx).Set(*v2)
|
|
} else {
|
|
newArray.Index(idx).Set(v1)
|
|
}
|
|
}
|
|
}
|
|
return &newArray
|
|
}
|
|
} else {
|
|
for _, k := range inValue.MapKeys() {
|
|
v := makeJSONType(inValue.MapIndex(k))
|
|
if v != nil {
|
|
inValue.SetMapIndex(k, *v)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
case reflect.Slice:
|
|
if inType.Elem().Kind() != reflect.Uint8 {
|
|
for i := inValue.Len() - 1; i >= 0; i-- {
|
|
v := makeJSONType(inValue.Index(i))
|
|
if v != nil && inValue.Index(i).CanSet() {
|
|
inValue.Index(i).Set(*v)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
case reflect.Struct:
|
|
for i := inType.NumField() - 1; i >= 0; i-- {
|
|
f := inType.Field(i)
|
|
if f.Anonymous {
|
|
v := makeJSONType(inValue.Field(i))
|
|
if v != nil && inValue.Field(i).CanSet() {
|
|
inValue.Field(i).Set(*v)
|
|
}
|
|
} else {
|
|
if f.Name[0] >= 65 && f.Name[0] <= 90 {
|
|
v := makeJSONType(inValue.Field(i))
|
|
if v != nil && inValue.Field(i).CanSet() {
|
|
inValue.Field(i).Set(*v)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// 补充缺失的 Key 转换工具
|
|
func GetLowerName(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
return strings.ToLower(s[:1]) + s[1:]
|
|
}
|
|
|
|
func GetUpperName(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
return strings.ToUpper(s[:1]) + s[1:]
|
|
}
|
|
|
|
// 指针工具
|
|
func Ptr[T any](v T) *T { return &v }
|
|
|
|
// FixUpperCase (保留以支持历史复杂的 Key 转换需求)
|
|
func FixUpperCase(data []byte, excludesKeys []string) {
|
|
// 原有逻辑保持
|
|
n := len(data)
|
|
types, keys, tpos := make([]bool, 0), make([]string, 0), -1
|
|
for i := 0; i < n-1; i++ {
|
|
if tpos+1 >= len(types) {
|
|
types = append(types, false)
|
|
keys = append(keys, "")
|
|
}
|
|
switch data[i] {
|
|
case '{':
|
|
tpos++
|
|
types[tpos] = true
|
|
keys[tpos] = ""
|
|
case '}':
|
|
tpos--
|
|
case '[':
|
|
tpos++
|
|
types[tpos] = false
|
|
keys[tpos] = ""
|
|
case ']':
|
|
tpos--
|
|
case '"':
|
|
keyPos := -1
|
|
if i > 0 && (data[i-1] == '{' || (data[i-1] == ',' && tpos >= 0 && types[tpos])) {
|
|
keyPos = i + 1
|
|
}
|
|
i++
|
|
for ; i < n-1; i++ {
|
|
if data[i] == '\\' {
|
|
i++
|
|
continue
|
|
}
|
|
if data[i] == '"' {
|
|
if keyPos >= 0 && len(excludesKeys) > 0 {
|
|
keys[tpos] = string(data[keyPos:i])
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if keyPos >= 0 && (data[keyPos] >= 'A' && data[keyPos] <= 'Z') {
|
|
excluded := false
|
|
if len(excludesKeys) > 0 {
|
|
checkStr := strings.Join(keys[0:tpos+1], ".")
|
|
for _, ek := range excludesKeys {
|
|
if strings.HasSuffix(ek, ".") {
|
|
excluded = strings.HasPrefix(checkStr, ek)
|
|
} else {
|
|
excluded = checkStr == ek
|
|
}
|
|
if excluded {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !excluded {
|
|
hasLower := false
|
|
for _, b := range data[keyPos:i] {
|
|
if b >= 'a' && b <= 'z' {
|
|
hasLower = true
|
|
break
|
|
}
|
|
}
|
|
if hasLower {
|
|
data[keyPos] |= 0x20
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeExcludeUpperKeys(data any, prefix string, level int) []string {
|
|
if level > 100 {
|
|
return nil
|
|
}
|
|
if prefix != "" {
|
|
prefix += "."
|
|
}
|
|
outs := make([]string, 0)
|
|
var v reflect.Value
|
|
if rv, ok := data.(reflect.Value); ok {
|
|
v = rv
|
|
} else {
|
|
v = reflect.ValueOf(data)
|
|
}
|
|
v = RealValue(v)
|
|
if !v.IsValid() {
|
|
return nil
|
|
}
|
|
t := v.Type()
|
|
switch t.Kind() {
|
|
case reflect.Map:
|
|
for _, k := range v.MapKeys() {
|
|
r := makeExcludeUpperKeys(v.MapIndex(k), prefix+fmt.Sprint(k.Interface()), level+1)
|
|
if len(r) > 0 {
|
|
outs = append(outs, r...)
|
|
}
|
|
}
|
|
case reflect.Struct:
|
|
for i := 0; i < t.NumField(); i++ {
|
|
f := t.Field(i)
|
|
if f.Anonymous {
|
|
r := makeExcludeUpperKeys(v.Field(i), strings.TrimSuffix(prefix, "."), level+1)
|
|
if len(r) > 0 {
|
|
outs = append(outs, r...)
|
|
}
|
|
} else if f.IsExported() {
|
|
tag := string(f.Tag)
|
|
if strings.Contains(tag, "keepKey") {
|
|
outs = append(outs, prefix+f.Name)
|
|
}
|
|
if strings.Contains(tag, "keepSubKey") {
|
|
outs = append(outs, prefix+f.Name+".")
|
|
}
|
|
r := makeExcludeUpperKeys(v.Field(i), prefix+f.Name, level+1)
|
|
if len(r) > 0 {
|
|
outs = append(outs, r...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return outs
|
|
}
|