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  }