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  }