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