gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/encoding/tags.go (about) 1 // This code is based on encoding/json and gorilla/schema 2 3 package encoding 4 5 import ( 6 "reflect" 7 "strconv" 8 "strings" 9 "unicode" 10 ) 11 12 var ( 13 Tags []string 14 ) 15 16 const ( 17 TagName = "rethinkdb" 18 OldTagName = "gorethink" 19 JSONTagName = "json" 20 RefTagName = "rethinkdb_ref" 21 OldRefTagName = "gorethink_ref" 22 ) 23 24 // tagOptions is the string following a comma in a struct field's 25 // tag, or the empty string. It does not include the leading comma. 26 type tagOptions string 27 28 func getTag(sf reflect.StructField) string { 29 if Tags == nil { 30 value := sf.Tag.Get(TagName) 31 if value == "" { 32 return sf.Tag.Get(OldTagName) 33 } 34 return value 35 } 36 37 for _, tagName := range Tags { 38 if tag := sf.Tag.Get(tagName); tag != "" { 39 return tag 40 } 41 } 42 43 return "" 44 } 45 46 func getRefTag(sf reflect.StructField) string { 47 value := sf.Tag.Get(RefTagName) 48 if value == "" { 49 return sf.Tag.Get(OldRefTagName) 50 } 51 return value 52 } 53 54 // parseTag splits a struct field's tag into its name and 55 // comma-separated options. 56 func parseTag(tag string) (string, tagOptions) { 57 if idx := strings.Index(tag, ","); idx != -1 { 58 return tag[:idx], tagOptions(tag[idx+1:]) 59 } 60 return tag, tagOptions("") 61 } 62 63 func parseCompoundIndex(tag string) (string, int, bool) { 64 lIdx := strings.Index(tag, "[") 65 rIdx := strings.Index(tag, "]") 66 if lIdx > 1 && rIdx > lIdx+1 { 67 if elemIndex_, err := strconv.ParseInt(tag[lIdx+1:rIdx], 10, 64); err == nil { 68 return tag[:lIdx], int(elemIndex_), true 69 } 70 } 71 72 return tag, 0, false 73 } 74 75 func isValidTag(s string) bool { 76 if s == "" { 77 return false 78 } 79 for _, c := range s { 80 switch { 81 case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): 82 // Backslash and quote chars are reserved, but 83 // otherwise any punctuation chars are allowed 84 // in a tag name. 85 default: 86 if !unicode.IsLetter(c) && !unicode.IsDigit(c) { 87 return false 88 } 89 } 90 } 91 return true 92 } 93 94 // Contains returns whether checks that a comma-separated list of options 95 // contains a particular substr flag. substr must be surrounded by a 96 // string boundary or commas. 97 func (o tagOptions) Contains(optionName string) bool { 98 if len(o) == 0 { 99 return false 100 } 101 s := string(o) 102 for s != "" { 103 var next string 104 i := strings.Index(s, ",") 105 if i >= 0 { 106 s, next = s[:i], s[i+1:] 107 } 108 if s == optionName { 109 return true 110 } 111 s = next 112 } 113 return false 114 }