refactor(serialization): small optimization

This commit is contained in:
yusing
2025-10-03 23:08:22 +08:00
parent 1e0c7a15d8
commit 42e7adbf86

View File

@@ -135,7 +135,9 @@ func fnv1IgnoreCaseSnake(s string) uint32 {
prime32 uint32 = 16777619 prime32 uint32 = 16777619
) )
hash := offset32 hash := offset32
for _, r := range s { // range over bytes instead of runes
for i := range s {
r := s[i]
if r == '_' { if r == '_' {
continue continue
} }
@@ -202,7 +204,10 @@ func initTypeKeyFieldIndexesMap(t reflect.Type) typeInfo {
for i := range numFields { for i := range numFields {
field := t.Field(i) field := t.Field(i)
if field.Tag.Get(tagDeserialize) == "-" || field.Tag.Get(tagJSON) == "-" { deserializeTag := field.Tag.Get(tagDeserialize)
jsonTag := field.Tag.Get(tagJSON)
if deserializeTag == "-" || jsonTag == "-" {
continue continue
} }
@@ -229,10 +234,7 @@ func initTypeKeyFieldIndexesMap(t reflect.Type) typeInfo {
} }
notAnonymousStruct: notAnonymousStruct:
var key string var key string
if jsonTag, ok := field.Tag.Lookup(tagJSON); ok { if jsonTag != "" {
if jsonTag == "-" {
continue
}
key = jsonTag key = jsonTag
if idxComma := strings.Index(key, ","); idxComma != -1 { if idxComma := strings.Index(key, ","); idxComma != -1 {
key = key[:idxComma] key = key[:idxComma]
@@ -247,8 +249,8 @@ func initTypeKeyFieldIndexesMap(t reflect.Type) typeInfo {
_, hasValidateTag = field.Tag.Lookup(tagValidate) _, hasValidateTag = field.Tag.Lookup(tagValidate)
} }
aliases, ok := field.Tag.Lookup(tagAliases) aliases := field.Tag.Get(tagAliases)
if ok { if aliases != "" {
for alias := range strings.SplitSeq(aliases, ",") { for alias := range strings.SplitSeq(aliases, ",") {
keyFieldIndexes[fnv1IgnoreCaseSnake(alias)] = field.Index keyFieldIndexes[fnv1IgnoreCaseSnake(alias)] = field.Index
fieldNames[alias] = struct{}{} fieldNames[alias] = struct{}{}
@@ -500,12 +502,15 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gpe
dst.SetString(src) dst.SetString(src)
return true, nil return true, nil
} }
switch dstT {
case reflect.TypeFor[time.Duration](): // Early return for empty string
if src == "" { if src == "" {
dst.SetZero() dst.SetZero()
return true, nil return true, nil
} }
switch dstT {
case reflect.TypeFor[time.Duration]():
d, err := time.ParseDuration(src) d, err := time.ParseDuration(src)
if err != nil { if err != nil {
return true, gperr.Wrap(err) return true, gperr.Wrap(err)
@@ -514,6 +519,7 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gpe
return true, nil return true, nil
default: default:
} }
if gi.ReflectIsNumeric(dst) || dst.Kind() == reflect.Bool { if gi.ReflectIsNumeric(dst) || dst.Kind() == reflect.Bool {
err := gi.ReflectStrToNumBool(dst, src) err := gi.ReflectStrToNumBool(dst, src)
if err != nil { if err != nil {
@@ -521,17 +527,32 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gpe
} }
return true, nil return true, nil
} }
// check if (*T).Convertor is implemented // check if (*T).Convertor is implemented
if dst.Addr().Type().Implements(parserType) { if dst.Addr().Type().Implements(parserType) {
parser := dst.Addr().Interface().(strutils.Parser) parser := dst.Addr().Interface().(strutils.Parser)
return true, gperr.Wrap(parser.Parse(src)) return true, gperr.Wrap(parser.Parse(src))
} }
// yaml like // yaml like
var tmp any var tmp any
switch dst.Kind() { switch dst.Kind() {
case reflect.Slice: case reflect.Slice:
src = strings.TrimSpace(src) // Avoid unnecessary TrimSpace if we can detect the format early
isMultiline := strings.ContainsRune(src, '\n') srcLen := len(src)
if srcLen == 0 {
return true, nil
}
// Check for multiline without allocating
isMultiline := false
for i := range srcLen {
if src[i] == '\n' {
isMultiline = true
break
}
}
// one liner is comma separated list // one liner is comma separated list
if !isMultiline && src[0] != '-' { if !isMultiline && src[0] != '-' {
values := strutils.CommaSeperatedList(src) values := strutils.CommaSeperatedList(src)
@@ -548,6 +569,7 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gpe
} }
return true, nil return true, nil
} }
sl := []any{} sl := []any{}
err := yaml.Unmarshal([]byte(src), &sl) err := yaml.Unmarshal([]byte(src), &sl)
if err != nil { if err != nil {