gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/encoding/cache.go (about) 1 // This code is based on encoding/json and gorilla/schema 2 3 package encoding 4 5 import ( 6 "reflect" 7 "sort" 8 "sync" 9 "time" 10 ) 11 12 // A field represents a single field found in a struct. 13 type field struct { 14 name string 15 nameBytes []byte // []byte(name) 16 equalFold func(s, t []byte) bool 17 18 tag bool 19 index []int 20 typ reflect.Type 21 omitEmpty bool 22 quoted bool 23 reference bool 24 refName string 25 compound bool 26 compoundIndex int 27 } 28 29 func fillField(f field) field { 30 f.nameBytes = []byte(f.name) 31 f.equalFold = foldFunc(f.nameBytes) 32 33 return f 34 } 35 36 // byName sorts field by name, breaking ties with depth, 37 // then breaking ties with "name came from tag", then 38 // breaking ties with index sequence. 39 type byName []field 40 41 func (x byName) Len() int { return len(x) } 42 43 func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 44 45 func (x byName) Less(i, j int) bool { 46 if x[i].name != x[j].name { 47 return x[i].name < x[j].name 48 } 49 if len(x[i].index) != len(x[j].index) { 50 return len(x[i].index) < len(x[j].index) 51 } 52 if x[i].tag != x[j].tag { 53 return x[i].tag 54 } 55 return byIndex(x).Less(i, j) 56 } 57 58 // byIndex sorts field by index sequence. 59 type byIndex []field 60 61 func (x byIndex) Len() int { return len(x) } 62 63 func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 64 65 func (x byIndex) Less(i, j int) bool { 66 for k, xik := range x[i].index { 67 if k >= len(x[j].index) { 68 return false 69 } 70 if xik != x[j].index[k] { 71 return xik < x[j].index[k] 72 } 73 } 74 return len(x[i].index) < len(x[j].index) 75 } 76 77 // typeFields returns a list of fields that should be recognized for the given type. 78 // The algorithm is breadth-first search over the set of structs to include - the top struct 79 // and then any reachable anonymous structs. 80 func typeFields(t reflect.Type) []field { 81 // Anonymous fields to explore at the current level and the next. 82 current := []field{} 83 next := []field{{typ: t}} 84 85 // Count of queued names for current level and the next. 86 count := map[reflect.Type]int{} 87 nextCount := map[reflect.Type]int{} 88 89 // Types already visited at an earlier level. 90 visited := map[reflect.Type]bool{} 91 92 // Fields found. 93 var fields []field 94 95 for len(next) > 0 { 96 current, next = next, current[:0] 97 count, nextCount = nextCount, map[reflect.Type]int{} 98 99 for _, f := range current { 100 if visited[f.typ] { 101 continue 102 } 103 visited[f.typ] = true 104 105 // Scan f.typ for fields to include. 106 for i := 0; i < f.typ.NumField(); i++ { 107 sf := f.typ.Field(i) 108 if sf.PkgPath != "" && !sf.Anonymous { // unexported 109 continue 110 } 111 // Extract field name from tag 112 tag := getTag(sf) 113 if tag == "-" { 114 continue 115 } 116 name, opts := parseTag(tag) 117 name, compoundIndex, isCompound := parseCompoundIndex(name) 118 if !isValidTag(name) { 119 name = "" 120 } 121 // Extract referenced field from tags 122 refTag := getRefTag(sf) 123 ref, _ := parseTag(refTag) 124 if !isValidTag(ref) { 125 ref = "" 126 } 127 128 index := make([]int, len(f.index)+1) 129 copy(index, f.index) 130 index[len(f.index)] = i 131 132 ft := sf.Type 133 if ft.Name() == "" && ft.Kind() == reflect.Ptr { 134 // Follow pointer. 135 ft = ft.Elem() 136 } 137 138 // Record found field and index sequence. 139 if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct || isPseudoType(ft) { 140 tagged := name != "" 141 if name == "" { 142 name = sf.Name 143 } 144 fields = append(fields, fillField(field{ 145 name: name, 146 tag: tagged, 147 index: index, 148 typ: ft, 149 omitEmpty: opts.Contains("omitempty"), 150 reference: opts.Contains("reference"), 151 refName: ref, 152 compound: isCompound, 153 compoundIndex: compoundIndex, 154 })) 155 if count[f.typ] > 1 { 156 // If there were multiple instances, add a second, 157 // so that the annihilation code will see a duplicate. 158 // It only cares about the distinction between 1 or 2, 159 // so don't bother generating any more copies. 160 fields = append(fields, fields[len(fields)-1]) 161 } 162 continue 163 } 164 165 // Record new anonymous struct to explore in next round. 166 nextCount[ft]++ 167 if nextCount[ft] == 1 { 168 next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) 169 } 170 } 171 } 172 } 173 174 sort.Sort(byName(fields)) 175 176 // Delete all fields that are hidden by the Go rules for embedded fields, 177 // except that fields with valid tags are promoted. 178 179 // The fields are sorted in primary order of name, secondary order 180 // of field index length. Loop over names; for each name, delete 181 // hidden fields by choosing the one dominant field that survives. 182 out := fields[:0] 183 for advance, i := 0, 0; i < len(fields); i += advance { 184 // One iteration per name. 185 // Find the sequence of fields with the name of this first field. 186 fi := fields[i] 187 for advance = 1; i+advance < len(fields); advance++ { 188 fj := fields[i+advance] 189 if fj.name != fi.name { 190 break 191 } 192 if fi.compound && fj.compound && fi.compoundIndex != fj.compoundIndex { 193 break 194 } 195 196 } 197 if advance == 1 { // Only one field with this name 198 out = append(out, fi) 199 continue 200 } 201 dominant, ok := dominantField(fields[i : i+advance]) 202 if ok { 203 out = append(out, dominant) 204 } 205 } 206 207 fields = out 208 sort.Sort(byIndex(fields)) 209 210 return fields 211 } 212 213 func isPseudoType(t reflect.Type) bool { 214 return t == reflect.TypeOf(time.Time{}) 215 } 216 217 // dominantField looks through the fields, all of which are known to 218 // have the same name, to find the single field that dominates the 219 // others using Go's embedding rules, modified by the presence of 220 // valid tags. If there are multiple top-level fields, the boolean 221 // will be false: This condition is an error in Go and we skip all 222 // the fields. 223 func dominantField(fields []field) (field, bool) { 224 // The fields are sorted in increasing index-length order. The winner 225 // must therefore be one with the shortest index length. Drop all 226 // longer entries, which is easy: just truncate the slice. 227 length := len(fields[0].index) 228 tagged := -1 // Index of first tagged field. 229 for i, f := range fields { 230 if len(f.index) > length { 231 fields = fields[:i] 232 break 233 } 234 if f.tag { 235 if tagged >= 0 { 236 // Multiple tagged fields at the same level: conflict. 237 // Return no field. 238 return field{}, false 239 } 240 tagged = i 241 } 242 } 243 if tagged >= 0 { 244 return fields[tagged], true 245 } 246 // All remaining fields have the same length. If there's more than one, 247 // we have a conflict (two fields named "X" at the same level) and we 248 // return no field. 249 if len(fields) > 1 { 250 return field{}, false 251 } 252 return fields[0], true 253 } 254 255 var fieldCache struct { 256 sync.RWMutex 257 m map[reflect.Type][]field 258 } 259 260 // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 261 func cachedTypeFields(t reflect.Type) []field { 262 fieldCache.RLock() 263 f := fieldCache.m[t] 264 fieldCache.RUnlock() 265 if f != nil { 266 return f 267 } 268 269 // Compute fields without lock. 270 // Might duplicate effort but won't hold other computations back. 271 f = typeFields(t) 272 if f == nil { 273 f = []field{} 274 } 275 276 fieldCache.Lock() 277 if fieldCache.m == nil { 278 fieldCache.m = map[reflect.Type][]field{} 279 } 280 fieldCache.m[t] = f 281 fieldCache.Unlock() 282 return f 283 }