reflect.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // Package reflectx implements extensions to the standard reflect lib suitable
  2. // for implementing marshalling and unmarshalling packages. The main Mapper type
  3. // allows for Go-compatible named attribute access, including accessing embedded
  4. // struct attributes and the ability to use functions and struct tags to
  5. // customize field names.
  6. //
  7. package reflectx
  8. import (
  9. "reflect"
  10. "runtime"
  11. "strings"
  12. "sync"
  13. )
  14. // A FieldInfo is metadata for a struct field.
  15. type FieldInfo struct {
  16. Index []int
  17. Path string
  18. Field reflect.StructField
  19. Zero reflect.Value
  20. Name string
  21. Options map[string]string
  22. Embedded bool
  23. Children []*FieldInfo
  24. Parent *FieldInfo
  25. }
  26. // A StructMap is an index of field metadata for a struct.
  27. type StructMap struct {
  28. Tree *FieldInfo
  29. Index []*FieldInfo
  30. Paths map[string]*FieldInfo
  31. Names map[string]*FieldInfo
  32. }
  33. // GetByPath returns a *FieldInfo for a given string path.
  34. func (f StructMap) GetByPath(path string) *FieldInfo {
  35. return f.Paths[path]
  36. }
  37. // GetByTraversal returns a *FieldInfo for a given integer path. It is
  38. // analogous to reflect.FieldByIndex, but using the cached traversal
  39. // rather than re-executing the reflect machinery each time.
  40. func (f StructMap) GetByTraversal(index []int) *FieldInfo {
  41. if len(index) == 0 {
  42. return nil
  43. }
  44. tree := f.Tree
  45. for _, i := range index {
  46. if i >= len(tree.Children) || tree.Children[i] == nil {
  47. return nil
  48. }
  49. tree = tree.Children[i]
  50. }
  51. return tree
  52. }
  53. // Mapper is a general purpose mapper of names to struct fields. A Mapper
  54. // behaves like most marshallers in the standard library, obeying a field tag
  55. // for name mapping but also providing a basic transform function.
  56. type Mapper struct {
  57. cache map[reflect.Type]*StructMap
  58. tagName string
  59. tagMapFunc func(string) string
  60. mapFunc func(string) string
  61. mutex sync.Mutex
  62. }
  63. // NewMapper returns a new mapper using the tagName as its struct field tag.
  64. // If tagName is the empty string, it is ignored.
  65. func NewMapper(tagName string) *Mapper {
  66. return &Mapper{
  67. cache: make(map[reflect.Type]*StructMap),
  68. tagName: tagName,
  69. }
  70. }
  71. // NewMapperTagFunc returns a new mapper which contains a mapper for field names
  72. // AND a mapper for tag values. This is useful for tags like json which can
  73. // have values like "name,omitempty".
  74. func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
  75. return &Mapper{
  76. cache: make(map[reflect.Type]*StructMap),
  77. tagName: tagName,
  78. mapFunc: mapFunc,
  79. tagMapFunc: tagMapFunc,
  80. }
  81. }
  82. // NewMapperFunc returns a new mapper which optionally obeys a field tag and
  83. // a struct field name mapper func given by f. Tags will take precedence, but
  84. // for any other field, the mapped name will be f(field.Name)
  85. func NewMapperFunc(tagName string, f func(string) string) *Mapper {
  86. return &Mapper{
  87. cache: make(map[reflect.Type]*StructMap),
  88. tagName: tagName,
  89. mapFunc: f,
  90. }
  91. }
  92. // TypeMap returns a mapping of field strings to int slices representing
  93. // the traversal down the struct to reach the field.
  94. func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
  95. m.mutex.Lock()
  96. mapping, ok := m.cache[t]
  97. if !ok {
  98. mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
  99. m.cache[t] = mapping
  100. }
  101. m.mutex.Unlock()
  102. return mapping
  103. }
  104. // FieldMap returns the mapper's mapping of field names to reflect values. Panics
  105. // if v's Kind is not Struct, or v is not Indirectable to a struct kind.
  106. func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
  107. v = reflect.Indirect(v)
  108. mustBe(v, reflect.Struct)
  109. r := map[string]reflect.Value{}
  110. tm := m.TypeMap(v.Type())
  111. for tagName, fi := range tm.Names {
  112. r[tagName] = FieldByIndexes(v, fi.Index)
  113. }
  114. return r
  115. }
  116. // FieldByName returns a field by its mapped name as a reflect.Value.
  117. // Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
  118. // Returns zero Value if the name is not found.
  119. func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
  120. v = reflect.Indirect(v)
  121. mustBe(v, reflect.Struct)
  122. tm := m.TypeMap(v.Type())
  123. fi, ok := tm.Names[name]
  124. if !ok {
  125. return v
  126. }
  127. return FieldByIndexes(v, fi.Index)
  128. }
  129. // FieldsByName returns a slice of values corresponding to the slice of names
  130. // for the value. Panics if v's Kind is not Struct or v is not Indirectable
  131. // to a struct Kind. Returns zero Value for each name not found.
  132. func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
  133. v = reflect.Indirect(v)
  134. mustBe(v, reflect.Struct)
  135. tm := m.TypeMap(v.Type())
  136. vals := make([]reflect.Value, 0, len(names))
  137. for _, name := range names {
  138. fi, ok := tm.Names[name]
  139. if !ok {
  140. vals = append(vals, *new(reflect.Value))
  141. } else {
  142. vals = append(vals, FieldByIndexes(v, fi.Index))
  143. }
  144. }
  145. return vals
  146. }
  147. // TraversalsByName returns a slice of int slices which represent the struct
  148. // traversals for each mapped name. Panics if t is not a struct or Indirectable
  149. // to a struct. Returns empty int slice for each name not found.
  150. func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
  151. r := make([][]int, 0, len(names))
  152. m.TraversalsByNameFunc(t, names, func(_ int, i []int) error {
  153. if i == nil {
  154. r = append(r, []int{})
  155. } else {
  156. r = append(r, i)
  157. }
  158. return nil
  159. })
  160. return r
  161. }
  162. // TraversalsByNameFunc traverses the mapped names and calls fn with the index of
  163. // each name and the struct traversal represented by that name. Panics if t is not
  164. // a struct or Indirectable to a struct. Returns the first error returned by fn or nil.
  165. func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int) error) error {
  166. t = Deref(t)
  167. mustBe(t, reflect.Struct)
  168. tm := m.TypeMap(t)
  169. for i, name := range names {
  170. fi, ok := tm.Names[name]
  171. if !ok {
  172. if err := fn(i, nil); err != nil {
  173. return err
  174. }
  175. } else {
  176. if err := fn(i, fi.Index); err != nil {
  177. return err
  178. }
  179. }
  180. }
  181. return nil
  182. }
  183. // FieldByIndexes returns a value for the field given by the struct traversal
  184. // for the given value.
  185. func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
  186. for _, i := range indexes {
  187. v = reflect.Indirect(v).Field(i)
  188. // if this is a pointer and it's nil, allocate a new value and set it
  189. if v.Kind() == reflect.Ptr && v.IsNil() {
  190. alloc := reflect.New(Deref(v.Type()))
  191. v.Set(alloc)
  192. }
  193. if v.Kind() == reflect.Map && v.IsNil() {
  194. v.Set(reflect.MakeMap(v.Type()))
  195. }
  196. }
  197. return v
  198. }
  199. // FieldByIndexesReadOnly returns a value for a particular struct traversal,
  200. // but is not concerned with allocating nil pointers because the value is
  201. // going to be used for reading and not setting.
  202. func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
  203. for _, i := range indexes {
  204. v = reflect.Indirect(v).Field(i)
  205. }
  206. return v
  207. }
  208. // Deref is Indirect for reflect.Types
  209. func Deref(t reflect.Type) reflect.Type {
  210. if t.Kind() == reflect.Ptr {
  211. t = t.Elem()
  212. }
  213. return t
  214. }
  215. // -- helpers & utilities --
  216. type kinder interface {
  217. Kind() reflect.Kind
  218. }
  219. // mustBe checks a value against a kind, panicing with a reflect.ValueError
  220. // if the kind isn't that which is required.
  221. func mustBe(v kinder, expected reflect.Kind) {
  222. if k := v.Kind(); k != expected {
  223. panic(&reflect.ValueError{Method: methodName(), Kind: k})
  224. }
  225. }
  226. // methodName returns the caller of the function calling methodName
  227. func methodName() string {
  228. pc, _, _, _ := runtime.Caller(2)
  229. f := runtime.FuncForPC(pc)
  230. if f == nil {
  231. return "unknown method"
  232. }
  233. return f.Name()
  234. }
  235. type typeQueue struct {
  236. t reflect.Type
  237. fi *FieldInfo
  238. pp string // Parent path
  239. }
  240. // A copying append that creates a new slice each time.
  241. func apnd(is []int, i int) []int {
  242. x := make([]int, len(is)+1)
  243. copy(x, is)
  244. x[len(x)-1] = i
  245. return x
  246. }
  247. type mapf func(string) string
  248. // parseName parses the tag and the target name for the given field using
  249. // the tagName (eg 'json' for `json:"foo"` tags), mapFunc for mapping the
  250. // field's name to a target name, and tagMapFunc for mapping the tag to
  251. // a target name.
  252. func parseName(field reflect.StructField, tagName string, mapFunc, tagMapFunc mapf) (tag, fieldName string) {
  253. // first, set the fieldName to the field's name
  254. fieldName = field.Name
  255. // if a mapFunc is set, use that to override the fieldName
  256. if mapFunc != nil {
  257. fieldName = mapFunc(fieldName)
  258. }
  259. // if there's no tag to look for, return the field name
  260. if tagName == "" {
  261. return "", fieldName
  262. }
  263. // if this tag is not set using the normal convention in the tag,
  264. // then return the fieldname.. this check is done because according
  265. // to the reflect documentation:
  266. // If the tag does not have the conventional format,
  267. // the value returned by Get is unspecified.
  268. // which doesn't sound great.
  269. if !strings.Contains(string(field.Tag), tagName+":") {
  270. return "", fieldName
  271. }
  272. // at this point we're fairly sure that we have a tag, so lets pull it out
  273. tag = field.Tag.Get(tagName)
  274. // if we have a mapper function, call it on the whole tag
  275. // XXX: this is a change from the old version, which pulled out the name
  276. // before the tagMapFunc could be run, but I think this is the right way
  277. if tagMapFunc != nil {
  278. tag = tagMapFunc(tag)
  279. }
  280. // finally, split the options from the name
  281. parts := strings.Split(tag, ",")
  282. fieldName = parts[0]
  283. return tag, fieldName
  284. }
  285. // parseOptions parses options out of a tag string, skipping the name
  286. func parseOptions(tag string) map[string]string {
  287. parts := strings.Split(tag, ",")
  288. options := make(map[string]string, len(parts))
  289. if len(parts) > 1 {
  290. for _, opt := range parts[1:] {
  291. // short circuit potentially expensive split op
  292. if strings.Contains(opt, "=") {
  293. kv := strings.Split(opt, "=")
  294. options[kv[0]] = kv[1]
  295. continue
  296. }
  297. options[opt] = ""
  298. }
  299. }
  300. return options
  301. }
  302. // getMapping returns a mapping for the t type, using the tagName, mapFunc and
  303. // tagMapFunc to determine the canonical names of fields.
  304. func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc mapf) *StructMap {
  305. m := []*FieldInfo{}
  306. root := &FieldInfo{}
  307. queue := []typeQueue{}
  308. queue = append(queue, typeQueue{Deref(t), root, ""})
  309. QueueLoop:
  310. for len(queue) != 0 {
  311. // pop the first item off of the queue
  312. tq := queue[0]
  313. queue = queue[1:]
  314. // ignore recursive field
  315. for p := tq.fi.Parent; p != nil; p = p.Parent {
  316. if tq.fi.Field.Type == p.Field.Type {
  317. continue QueueLoop
  318. }
  319. }
  320. nChildren := 0
  321. if tq.t.Kind() == reflect.Struct {
  322. nChildren = tq.t.NumField()
  323. }
  324. tq.fi.Children = make([]*FieldInfo, nChildren)
  325. // iterate through all of its fields
  326. for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
  327. f := tq.t.Field(fieldPos)
  328. // parse the tag and the target name using the mapping options for this field
  329. tag, name := parseName(f, tagName, mapFunc, tagMapFunc)
  330. // if the name is "-", disabled via a tag, skip it
  331. if name == "-" {
  332. continue
  333. }
  334. fi := FieldInfo{
  335. Field: f,
  336. Name: name,
  337. Zero: reflect.New(f.Type).Elem(),
  338. Options: parseOptions(tag),
  339. }
  340. // if the path is empty this path is just the name
  341. if tq.pp == "" {
  342. fi.Path = fi.Name
  343. } else {
  344. fi.Path = tq.pp + "." + fi.Name
  345. }
  346. // skip unexported fields
  347. if len(f.PkgPath) != 0 && !f.Anonymous {
  348. continue
  349. }
  350. // bfs search of anonymous embedded structs
  351. if f.Anonymous {
  352. pp := tq.pp
  353. if tag != "" {
  354. pp = fi.Path
  355. }
  356. fi.Embedded = true
  357. fi.Index = apnd(tq.fi.Index, fieldPos)
  358. nChildren := 0
  359. ft := Deref(f.Type)
  360. if ft.Kind() == reflect.Struct {
  361. nChildren = ft.NumField()
  362. }
  363. fi.Children = make([]*FieldInfo, nChildren)
  364. queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
  365. } else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
  366. fi.Index = apnd(tq.fi.Index, fieldPos)
  367. fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
  368. queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
  369. }
  370. fi.Index = apnd(tq.fi.Index, fieldPos)
  371. fi.Parent = tq.fi
  372. tq.fi.Children[fieldPos] = &fi
  373. m = append(m, &fi)
  374. }
  375. }
  376. flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
  377. for _, fi := range flds.Index {
  378. // check if nothing has already been pushed with the same path
  379. // sometimes you can choose to override a type using embedded struct
  380. fld, ok := flds.Paths[fi.Path]
  381. if !ok || fld.Embedded {
  382. flds.Paths[fi.Path] = fi
  383. if fi.Name != "" && !fi.Embedded {
  384. flds.Names[fi.Path] = fi
  385. }
  386. }
  387. }
  388. return flds
  389. }