github.com/grbit/go-json@v0.11.0/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("json") 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 type StructTags []*StructTag 41 42 func (t StructTags) ExistsKey(key string) bool { 43 for _, tt := range t { 44 if tt.Key == key { 45 return true 46 } 47 } 48 return false 49 } 50 51 func isValidTag(s string) bool { 52 if s == "" { 53 return false 54 } 55 for _, c := range s { 56 switch { 57 case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): 58 // Backslash and quote chars are reserved, but 59 // otherwise any punctuation chars are allowed 60 // in a tag name. 61 case !unicode.IsLetter(c) && !unicode.IsDigit(c): 62 return false 63 } 64 } 65 return true 66 } 67 68 func StructTagFromField(field reflect.StructField) *StructTag { 69 keyName := field.Name 70 tag := getTag(field) 71 st := &StructTag{Field: field} 72 opts := strings.Split(tag, ",") 73 if len(opts) > 0 { 74 if opts[0] != "" && isValidTag(opts[0]) { 75 keyName = opts[0] 76 st.IsTaggedKey = true 77 } 78 } 79 st.Key = keyName 80 if len(opts) > 1 { 81 for _, opt := range opts[1:] { 82 switch opt { 83 case "omitempty": 84 st.IsOmitEmpty = true 85 case "string": 86 st.IsString = true 87 } 88 } 89 } 90 return st 91 }