| // Copyright 2016 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // Package fields provides a view of the fields of a struct that follows the Go | |
| // rules, amended to consider tags and case insensitivity. | |
| // | |
| // Usage | |
| // | |
| // First define a function that interprets tags: | |
| // | |
| // func parseTag(st reflect.StructTag) (name string, keep bool, other interface{}, err error) { ... } | |
| // | |
| // The function's return values describe whether to ignore the field | |
| // completely or provide an alternate name, as well as other data from the | |
| // parse that is stored to avoid re-parsing. | |
| // | |
| // Then define a function to validate the type: | |
| // | |
| // func validate(t reflect.Type) error { ... } | |
| // | |
| // Then, if necessary, define a function to specify leaf types - types | |
| // which should be considered one field and not be recursed into: | |
| // | |
| // func isLeafType(t reflect.Type) bool { ... } | |
| // | |
| // eg: | |
| // | |
| // func isLeafType(t reflect.Type) bool { | |
| // return t == reflect.TypeOf(time.Time{}) | |
| // } | |
| // | |
| // Next, construct a Cache, passing your functions. As its name suggests, a | |
| // Cache remembers validation and field information for a type, so subsequent | |
| // calls with the same type are very fast. | |
| // | |
| // cache := fields.NewCache(parseTag, validate, isLeafType) | |
| // | |
| // To get the fields of a struct type as determined by the above rules, call | |
| // the Fields method: | |
| // | |
| // fields, err := cache.Fields(reflect.TypeOf(MyStruct{})) | |
| // | |
| // The return value can be treated as a slice of Fields. | |
| // | |
| // Given a string, such as a key or column name obtained during unmarshalling, | |
| // call Match on the list of fields to find a field whose name is the best | |
| // match: | |
| // | |
| // field := fields.Match(name) | |
| // | |
| // Match looks for an exact match first, then falls back to a case-insensitive | |
| // comparison. | |
| package fields | |
| import ( | |
| "bytes" | |
| "errors" | |
| "reflect" | |
| "sort" | |
| "strings" | |
| "sync" | |
| ) | |
| // A Field records information about a struct field. | |
| type Field struct { | |
| Name string // effective field name | |
| NameFromTag bool // did Name come from a tag? | |
| Type reflect.Type // field type | |
| Index []int // index sequence, for reflect.Value.FieldByIndex | |
| ParsedTag interface{} // third return value of the parseTag function | |
| nameBytes []byte | |
| equalFold func(s, t []byte) bool | |
| } | |
| // ParseTagFunc is a function that accepts a struct tag and returns four values: an alternative name for the field | |
| // extracted from the tag, a boolean saying whether to keep the field or ignore it, additional data that is stored | |
| // with the field information to avoid having to parse the tag again, and an error. | |
| type ParseTagFunc func(reflect.StructTag) (name string, keep bool, other interface{}, err error) | |
| // ValidateFunc is a function that accepts a reflect.Type and returns an error if the struct type is invalid in any | |
| // way. | |
| type ValidateFunc func(reflect.Type) error | |
| // LeafTypesFunc is a function that accepts a reflect.Type and returns true if the struct type a leaf, or false if not. | |
| // TODO(deklerk): is this description accurate? | |
| type LeafTypesFunc func(reflect.Type) bool | |
| // A Cache records information about the fields of struct types. | |
| // | |
| // A Cache is safe for use by multiple goroutines. | |
| type Cache struct { | |
| parseTag ParseTagFunc | |
| validate ValidateFunc | |
| leafTypes LeafTypesFunc | |
| cache sync.Map // from reflect.Type to cacheValue | |
| } | |
| // NewCache constructs a Cache. | |
| // | |
| // Its first argument should be a function that accepts | |
| // a struct tag and returns four values: an alternative name for the field | |
| // extracted from the tag, a boolean saying whether to keep the field or ignore | |
| // it, additional data that is stored with the field information to avoid | |
| // having to parse the tag again, and an error. | |
| // | |
| // Its second argument should be a function that accepts a reflect.Type and | |
| // returns an error if the struct type is invalid in any way. For example, it | |
| // may check that all of the struct field tags are valid, or that all fields | |
| // are of an appropriate type. | |
| func NewCache(parseTag ParseTagFunc, validate ValidateFunc, leafTypes LeafTypesFunc) *Cache { | |
| if parseTag == nil { | |
| parseTag = func(reflect.StructTag) (string, bool, interface{}, error) { | |
| return "", true, nil, nil | |
| } | |
| } | |
| if validate == nil { | |
| validate = func(reflect.Type) error { | |
| return nil | |
| } | |
| } | |
| if leafTypes == nil { | |
| leafTypes = func(reflect.Type) bool { | |
| return false | |
| } | |
| } | |
| return &Cache{ | |
| parseTag: parseTag, | |
| validate: validate, | |
| leafTypes: leafTypes, | |
| } | |
| } | |
| // A fieldScan represents an item on the fieldByNameFunc scan work list. | |
| type fieldScan struct { | |
| typ reflect.Type | |
| index []int | |
| } | |
| // Fields returns all the exported fields of t, which must be a struct type. It | |
| // follows the standard Go rules for embedded fields, modified by the presence | |
| // of tags. The result is sorted lexicographically by index. | |
| // | |
| // These rules apply in the absence of tags: | |
| // Anonymous struct fields are treated as if their inner exported fields were | |
| // fields in the outer struct (embedding). The result includes all fields that | |
| // aren't shadowed by fields at higher level of embedding. If more than one | |
| // field with the same name exists at the same level of embedding, it is | |
| // excluded. An anonymous field that is not of struct type is treated as having | |
| // its type as its name. | |
| // | |
| // Tags modify these rules as follows: | |
| // A field's tag is used as its name. | |
| // An anonymous struct field with a name given in its tag is treated as | |
| // a field having that name, rather than an embedded struct (the struct's | |
| // fields will not be returned). | |
| // If more than one field with the same name exists at the same level of embedding, | |
| // but exactly one of them is tagged, then the tagged field is reported and the others | |
| // are ignored. | |
| func (c *Cache) Fields(t reflect.Type) (List, error) { | |
| if t.Kind() != reflect.Struct { | |
| panic("fields: Fields of non-struct type") | |
| } | |
| return c.cachedTypeFields(t) | |
| } | |
| // A List is a list of Fields. | |
| type List []Field | |
| // Match returns the field in the list whose name best matches the supplied | |
| // name, nor nil if no field does. If there is a field with the exact name, it | |
| // is returned. Otherwise the first field (sorted by index) whose name matches | |
| // case-insensitively is returned. | |
| func (l List) Match(name string) *Field { | |
| return l.MatchBytes([]byte(name)) | |
| } | |
| // MatchBytes is identical to Match, except that the argument is a byte slice. | |
| func (l List) MatchBytes(name []byte) *Field { | |
| var f *Field | |
| for i := range l { | |
| ff := &l[i] | |
| if bytes.Equal(ff.nameBytes, name) { | |
| return ff | |
| } | |
| if f == nil && ff.equalFold(ff.nameBytes, name) { | |
| f = ff | |
| } | |
| } | |
| return f | |
| } | |
| type cacheValue struct { | |
| fields List | |
| err error | |
| } | |
| // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. | |
| // This code has been copied and modified from | |
| // https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/encode.go. | |
| func (c *Cache) cachedTypeFields(t reflect.Type) (List, error) { | |
| var cv cacheValue | |
| x, ok := c.cache.Load(t) | |
| if ok { | |
| cv = x.(cacheValue) | |
| } else { | |
| if err := c.validate(t); err != nil { | |
| cv = cacheValue{nil, err} | |
| } else { | |
| f, err := c.typeFields(t) | |
| cv = cacheValue{List(f), err} | |
| } | |
| c.cache.Store(t, cv) | |
| } | |
| return cv.fields, cv.err | |
| } | |
| func (c *Cache) typeFields(t reflect.Type) ([]Field, error) { | |
| fields, err := c.listFields(t) | |
| if err != nil { | |
| return nil, err | |
| } | |
| sort.Sort(byName(fields)) | |
| // Delete all fields that are hidden by the Go rules for embedded fields. | |
| // The fields are sorted in primary order of name, secondary order of field | |
| // index length. So the first field with a given name is the dominant one. | |
| var out []Field | |
| for advance, i := 0, 0; i < len(fields); i += advance { | |
| // One iteration per name. | |
| // Find the sequence of fields with the name of this first field. | |
| fi := fields[i] | |
| name := fi.Name | |
| for advance = 1; i+advance < len(fields); advance++ { | |
| fj := fields[i+advance] | |
| if fj.Name != name { | |
| break | |
| } | |
| } | |
| // Find the dominant field, if any, out of all fields that have the same name. | |
| dominant, ok := dominantField(fields[i : i+advance]) | |
| if ok { | |
| out = append(out, dominant) | |
| } | |
| } | |
| sort.Sort(byIndex(out)) | |
| return out, nil | |
| } | |
| func (c *Cache) listFields(t reflect.Type) ([]Field, error) { | |
| // This uses the same condition that the Go language does: there must be a unique instance | |
| // of the match at a given depth level. If there are multiple instances of a match at the | |
| // same depth, they annihilate each other and inhibit any possible match at a lower level. | |
| // The algorithm is breadth first search, one depth level at a time. | |
| // The current and next slices are work queues: | |
| // current lists the fields to visit on this depth level, | |
| // and next lists the fields on the next lower level. | |
| current := []fieldScan{} | |
| next := []fieldScan{{typ: t}} | |
| // nextCount records the number of times an embedded type has been | |
| // encountered and considered for queueing in the 'next' slice. | |
| // We only queue the first one, but we increment the count on each. | |
| // If a struct type T can be reached more than once at a given depth level, | |
| // then it annihilates itself and need not be considered at all when we | |
| // process that next depth level. | |
| var nextCount map[reflect.Type]int | |
| // visited records the structs that have been considered already. | |
| // Embedded pointer fields can create cycles in the graph of | |
| // reachable embedded types; visited avoids following those cycles. | |
| // It also avoids duplicated effort: if we didn't find the field in an | |
| // embedded type T at level 2, we won't find it in one at level 4 either. | |
| visited := map[reflect.Type]bool{} | |
| var fields []Field // Fields found. | |
| for len(next) > 0 { | |
| current, next = next, current[:0] | |
| count := nextCount | |
| nextCount = nil | |
| // Process all the fields at this depth, now listed in 'current'. | |
| // The loop queues embedded fields found in 'next', for processing during the next | |
| // iteration. The multiplicity of the 'current' field counts is recorded | |
| // in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'. | |
| for _, scan := range current { | |
| t := scan.typ | |
| if visited[t] { | |
| // We've looked through this type before, at a higher level. | |
| // That higher level would shadow the lower level we're now at, | |
| // so this one can't be useful to us. Ignore it. | |
| continue | |
| } | |
| visited[t] = true | |
| for i := 0; i < t.NumField(); i++ { | |
| f := t.Field(i) | |
| exported := (f.PkgPath == "") | |
| // If a named field is unexported, ignore it. An anonymous | |
| // unexported field is processed, because it may contain | |
| // exported fields, which are visible. | |
| if !exported && !f.Anonymous { | |
| continue | |
| } | |
| // Examine the tag. | |
| tagName, keep, other, err := c.parseTag(f.Tag) | |
| if err != nil { | |
| return nil, err | |
| } | |
| if !keep { | |
| continue | |
| } | |
| if c.leafTypes(f.Type) { | |
| fields = append(fields, newField(f, tagName, other, scan.index, i)) | |
| continue | |
| } | |
| var ntyp reflect.Type | |
| if f.Anonymous { | |
| // Anonymous field of type T or *T. | |
| ntyp = f.Type | |
| if ntyp.Kind() == reflect.Ptr { | |
| ntyp = ntyp.Elem() | |
| } | |
| } | |
| // Record fields with a tag name, non-anonymous fields, or | |
| // anonymous non-struct fields. | |
| if tagName != "" || ntyp == nil || ntyp.Kind() != reflect.Struct { | |
| if !exported { | |
| continue | |
| } | |
| fields = append(fields, newField(f, tagName, other, scan.index, i)) | |
| if count[t] > 1 { | |
| // If there were multiple instances, add a second, | |
| // so that the annihilation code will see a duplicate. | |
| fields = append(fields, fields[len(fields)-1]) | |
| } | |
| continue | |
| } | |
| // Queue embedded struct fields for processing with next level, | |
| // but only if the embedded types haven't already been queued. | |
| if nextCount[ntyp] > 0 { | |
| nextCount[ntyp] = 2 // exact multiple doesn't matter | |
| continue | |
| } | |
| if nextCount == nil { | |
| nextCount = map[reflect.Type]int{} | |
| } | |
| nextCount[ntyp] = 1 | |
| if count[t] > 1 { | |
| nextCount[ntyp] = 2 // exact multiple doesn't matter | |
| } | |
| var index []int | |
| index = append(index, scan.index...) | |
| index = append(index, i) | |
| next = append(next, fieldScan{ntyp, index}) | |
| } | |
| } | |
| } | |
| return fields, nil | |
| } | |
| func newField(f reflect.StructField, tagName string, other interface{}, index []int, i int) Field { | |
| name := tagName | |
| if name == "" { | |
| name = f.Name | |
| } | |
| sf := Field{ | |
| Name: name, | |
| NameFromTag: tagName != "", | |
| Type: f.Type, | |
| ParsedTag: other, | |
| nameBytes: []byte(name), | |
| } | |
| sf.equalFold = foldFunc(sf.nameBytes) | |
| sf.Index = append(sf.Index, index...) | |
| sf.Index = append(sf.Index, i) | |
| return sf | |
| } | |
| // byName sorts fields using the following criteria, in order: | |
| // 1. name | |
| // 2. embedding depth | |
| // 3. tag presence (preferring a tagged field) | |
| // 4. index sequence. | |
| type byName []Field | |
| func (x byName) Len() int { return len(x) } | |
| func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | |
| func (x byName) Less(i, j int) bool { | |
| if x[i].Name != x[j].Name { | |
| return x[i].Name < x[j].Name | |
| } | |
| if len(x[i].Index) != len(x[j].Index) { | |
| return len(x[i].Index) < len(x[j].Index) | |
| } | |
| if x[i].NameFromTag != x[j].NameFromTag { | |
| return x[i].NameFromTag | |
| } | |
| return byIndex(x).Less(i, j) | |
| } | |
| // byIndex sorts field by index sequence. | |
| type byIndex []Field | |
| func (x byIndex) Len() int { return len(x) } | |
| func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | |
| func (x byIndex) Less(i, j int) bool { | |
| xi := x[i].Index | |
| xj := x[j].Index | |
| ln := len(xi) | |
| if l := len(xj); l < ln { | |
| ln = l | |
| } | |
| for k := 0; k < ln; k++ { | |
| if xi[k] != xj[k] { | |
| return xi[k] < xj[k] | |
| } | |
| } | |
| return len(xi) < len(xj) | |
| } | |
| // dominantField looks through the fields, all of which are known to have the | |
| // same name, to find the single field that dominates the others using Go's | |
| // embedding rules, modified by the presence of tags. If there are multiple | |
| // top-level fields, the boolean will be false: This condition is an error in | |
| // Go and we skip all the fields. | |
| func dominantField(fs []Field) (Field, bool) { | |
| // The fields are sorted in increasing index-length order, then by presence of tag. | |
| // That means that the first field is the dominant one. We need only check | |
| // for error cases: two fields at top level, either both tagged or neither tagged. | |
| if len(fs) > 1 && len(fs[0].Index) == len(fs[1].Index) && fs[0].NameFromTag == fs[1].NameFromTag { | |
| return Field{}, false | |
| } | |
| return fs[0], true | |
| } | |
| // ParseStandardTag extracts the sub-tag named by key, then parses it using the | |
| // de facto standard format introduced in encoding/json: | |
| // "-" means "ignore this tag". It must occur by itself. (parseStandardTag returns an error | |
| // in this case, whereas encoding/json accepts the "-" even if it is not alone.) | |
| // "<name>" provides an alternative name for the field | |
| // "<name>,opt1,opt2,..." specifies options after the name. | |
| // The options are returned as a []string. | |
| func ParseStandardTag(key string, t reflect.StructTag) (name string, keep bool, options []string, err error) { | |
| s := t.Get(key) | |
| parts := strings.Split(s, ",") | |
| if parts[0] == "-" { | |
| if len(parts) > 1 { | |
| return "", false, nil, errors.New(`"-" field tag with options`) | |
| } | |
| return "", false, nil, nil | |
| } | |
| if len(parts) > 1 { | |
| options = parts[1:] | |
| } | |
| return parts[0], true, options, nil | |
| } |