github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/runtime/struct_field.go (about) 1 package runtime 2 3 import ( 4 "reflect" 5 "strings" 6 "unicode" 7 ) 8 9 func getTag(field reflect.StructField) string { 10 return field.Tag.Get("php") 11 } 12 13 func IsIgnoredStructField(field reflect.StructField) bool { 14 if field.PkgPath != "" { 15 if field.Anonymous { 16 t := field.Type 17 if t.Kind() == reflect.Ptr { 18 t = t.Elem() 19 } 20 if t.Kind() != reflect.Struct { 21 return true 22 } 23 } else { 24 // private field 25 return true 26 } 27 } 28 tag := getTag(field) 29 return tag == "-" 30 } 31 32 type StructTag struct { 33 Key string 34 IsTaggedKey bool 35 IsOmitEmpty bool 36 IsString bool 37 Field reflect.StructField 38 } 39 40 func (s StructTag) Name() string { 41 if s.Key != "" { 42 return s.Key 43 } 44 return s.Field.Name 45 } 46 47 type StructTags []*StructTag 48 49 func (t StructTags) ExistsKey(key string) bool { 50 for _, tt := range t { 51 if tt.Key == key { 52 return true 53 } 54 } 55 return false 56 } 57 58 func isValidTag(s string) bool { 59 if s == "" { 60 return false 61 } 62 for _, c := range s { 63 switch { 64 case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): 65 // Backslash and quote chars are reserved, but 66 // otherwise any punctuation chars are allowed 67 // in a tag name. 68 case !unicode.IsLetter(c) && !unicode.IsDigit(c): 69 return false 70 } 71 } 72 return true 73 } 74 75 func StructTagFromField(field reflect.StructField) *StructTag { 76 keyName := field.Name 77 tag := getTag(field) 78 st := &StructTag{Field: field} 79 opts := strings.Split(tag, ",") 80 if len(opts) > 0 { 81 if opts[0] != "" && isValidTag(opts[0]) { 82 keyName = opts[0] 83 st.IsTaggedKey = true 84 } 85 } 86 st.Key = keyName 87 if len(opts) > 1 { 88 for _, opt := range opts[1:] { 89 switch opt { 90 case "omitempty": 91 st.IsOmitEmpty = true 92 case "string": 93 st.IsString = true 94 } 95 } 96 } 97 return st 98 }